1 /* Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
2  *
3  * Redistribution and use in source and binary forms, with or without
4  * modification, are permitted provided that the following conditions are
5  * met:
6  *     * Redistributions of source code must retain the above copyright
7  *       notice, this list of conditions and the following disclaimer.
8  *     * Redistributions in binary form must reproduce the above
9  *       copyright notice, this list of conditions and the following
10  *       disclaimer in the documentation and/or other materials provided
11  *       with the distribution.
12  *     * Neither the name of The Linux Foundation, nor the names of its
13  *       contributors may be used to endorse or promote products derived
14  *       from this software without specific prior written permission.
15  *
16  * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
17  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
20  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
23  * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
24  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
25  * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
26  * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  */
28 
29 #include <stdio.h>
30 #include <assert.h>
31 #include <errno.h>
32 #include <sys/time.h>
33 #include <string.h>
34 #include <pthread.h>
35 
36 #include <rpc/rpc.h>
37 #include <loc_api_rpc_glue.h>
38 #include "loc_api_sync_call.h"
39 
40 /* Logging */
41 #define LOG_TAG "LocSvc_api_rpc_glue"
42 // #define LOG_NDDEBUG 0
43 #ifndef USE_GLIB
44 #include <utils/Log.h>
45 #endif /* USE_GLIB */
46 
47 /***************************************************************************
48  *                 DATA FOR ASYNCHRONOUS RPC PROCESSING
49  **************************************************************************/
50 loc_sync_call_slot_array_s_type loc_sync_data;
51 
52 pthread_mutex_t loc_sync_call_mutex = PTHREAD_MUTEX_INITIALIZER;
53 boolean loc_sync_call_inited = 0;
54 
55 /*===========================================================================
56 
57 FUNCTION    loc_api_sync_call_init
58 
59 DESCRIPTION
60    Initialize this module
61 
62 DEPENDENCIES
63    N/A
64 
65 RETURN VALUE
66    none
67 
68 SIDE EFFECTS
69    N/A
70 
71 ===========================================================================*/
loc_api_sync_call_init()72 void loc_api_sync_call_init()
73 {
74    pthread_mutex_lock(&loc_sync_call_mutex);
75    if (loc_sync_call_inited == 1) {
76        pthread_mutex_unlock(&loc_sync_call_mutex);
77        return;
78    }
79    loc_sync_call_inited = 1;
80 
81    loc_sync_data.num_of_slots = LOC_SYNC_CALL_SLOTS_MAX;
82 
83    int i;
84    for (i = 0; i < loc_sync_data.num_of_slots; i++)
85    {
86       loc_sync_call_slot_s_type *slot = &loc_sync_data.slots[i];
87 
88       pthread_mutex_init(&slot->lock, NULL);
89       pthread_cond_init(&slot->loc_cb_arrived_cond, NULL);
90 
91       slot->not_available = 0;
92       slot->in_use = 0;
93       slot->loc_handle = -1;
94       slot->loc_cb_wait_event_mask = 0;       /* event to wait   */
95       slot->loc_cb_received_event_mask = 0;   /* received event   */
96    }
97 
98    pthread_mutex_unlock(&loc_sync_call_mutex);
99 }
100 
101 /*===========================================================================
102 
103 FUNCTION    loc_api_sync_call_destroy
104 
105 DESCRIPTION
106    Initialize this module
107 
108 DEPENDENCIES
109    N/A
110 
111 RETURN VALUE
112    none
113 
114 SIDE EFFECTS
115    N/A
116 
117 ===========================================================================*/
loc_api_sync_call_destroy()118 void loc_api_sync_call_destroy()
119 {
120    int i;
121 
122    pthread_mutex_lock(&loc_sync_call_mutex);
123    if (loc_sync_call_inited == 0) {
124        pthread_mutex_unlock(&loc_sync_call_mutex);
125        return;
126    }
127    loc_sync_call_inited = 0;
128 
129    for (i = 0; i < loc_sync_data.num_of_slots; i++)
130    {
131       loc_sync_call_slot_s_type *slot = &loc_sync_data.slots[i];
132 
133       pthread_mutex_lock(&slot->lock);
134 
135       slot->not_available = 1;
136 
137       pthread_mutex_unlock(&slot->lock);
138 
139       pthread_cond_destroy(&slot->loc_cb_arrived_cond);
140       pthread_mutex_destroy(&slot->lock);
141    }
142 
143    pthread_mutex_unlock(&loc_sync_call_mutex);
144 }
145 
146 /*===========================================================================
147 
148 FUNCTION    loc_match_callback
149 
150 DESCRIPTION
151    Checks if an awaited event has arrived
152 
153 RETURN VALUE
154    TRUE                 arrived
155    FALSE                not matching
156 
157 ===========================================================================*/
loc_match_callback(rpc_loc_event_mask_type wait_mask,rpc_loc_ioctl_e_type wait_ioctl,rpc_loc_event_mask_type event_mask,const rpc_loc_event_payload_u_type * callback_payload)158 static boolean loc_match_callback(
159       rpc_loc_event_mask_type             wait_mask,
160       rpc_loc_ioctl_e_type                wait_ioctl,
161       rpc_loc_event_mask_type             event_mask,
162       const rpc_loc_event_payload_u_type  *callback_payload
163 )
164 {
165    if ((event_mask & wait_mask) == 0) return FALSE;
166 
167    if (event_mask != RPC_LOC_EVENT_IOCTL_REPORT || wait_ioctl == 0 ||
168         ( (callback_payload != NULL) &&
169          callback_payload->rpc_loc_event_payload_u_type_u.ioctl_report.type == wait_ioctl) )
170       return TRUE;
171 
172    return FALSE;
173 }
174 
175 /*===========================================================================
176 
177 FUNCTION    loc_api_callback_process_sync_call
178 
179 DESCRIPTION
180    Wakes up blocked API calls to check if the needed callback has arrived
181 
182 DEPENDENCIES
183    N/A
184 
185 RETURN VALUE
186    none
187 
188 SIDE EFFECTS
189    N/A
190 
191 ===========================================================================*/
loc_api_callback_process_sync_call(rpc_loc_client_handle_type loc_handle,rpc_loc_event_mask_type loc_event,const rpc_loc_event_payload_u_type * loc_event_payload)192 void loc_api_callback_process_sync_call(
193       rpc_loc_client_handle_type            loc_handle,             /* handle of the client */
194       rpc_loc_event_mask_type               loc_event,              /* event mask           */
195       const rpc_loc_event_payload_u_type*   loc_event_payload       /* payload              */
196 )
197 {
198    int i;
199 
200    ALOGV("loc_handle = 0x%lx, loc_event = 0x%lx", loc_handle, loc_event);
201    for (i = 0; i < loc_sync_data.num_of_slots; i++)
202    {
203       loc_sync_call_slot_s_type *slot = &loc_sync_data.slots[i];
204 
205       pthread_mutex_lock(&slot->lock);
206 
207       if (slot->in_use &&
208           slot->signal_sent == 0 &&
209           slot->loc_handle == loc_handle &&
210           loc_match_callback(slot->loc_cb_wait_event_mask, slot->ioctl_type, loc_event, loc_event_payload))
211       {
212          memcpy(&slot->loc_cb_received_payload, loc_event_payload, sizeof (rpc_loc_event_payload_u_type));
213 
214          slot->loc_cb_received_event_mask = loc_event;
215 
216          ALOGV("signal slot %d in_use %d, loc_handle 0x%lx, event_mask 0x%1x, ioctl_type %d", i, slot->in_use, slot->loc_handle, (int) slot->loc_cb_wait_event_mask, (int) slot->ioctl_type);
217          pthread_cond_signal(&slot->loc_cb_arrived_cond);
218          slot->signal_sent = 1;
219 
220          pthread_mutex_unlock(&slot->lock);
221          break;
222       } else {
223          /* do nothing */
224       }
225 
226       pthread_mutex_unlock(&slot->lock);
227    }
228 }
229 
230 /*===========================================================================
231 
232 FUNCTION    loc_lock_a_slot
233 
234 DESCRIPTION
235    Allocates a buffer slot for the synchronous API call
236 
237 DEPENDENCIES
238    N/A
239 
240 RETURN VALUE
241    Select ID (>=0)     : successful
242    -1                  : buffer full
243 
244 SIDE EFFECTS
245    N/A
246 
247 ===========================================================================*/
loc_lock_a_slot()248 static int loc_lock_a_slot()
249 {
250    int i, select_id = -1; /* no free buffer */
251 
252    for (i = 0; i < loc_sync_data.num_of_slots; i++)
253    {
254       loc_sync_call_slot_s_type *slot = &loc_sync_data.slots[i];
255       if (pthread_mutex_trylock(&slot->lock) == EBUSY)
256       {
257          ALOGV("trylock EBUSY : %d", i);
258          continue;
259       }
260 
261       if (!slot->in_use && !slot->not_available)
262       {
263          select_id = i;
264          /* Return from here and leave the mutex locked.
265           * will unlock it in loc_unlock_slot()
266           */
267          break;
268       }
269       /* ALOGV("slot %d in_use = %d, not_available = %d : %d", i, slot->in_use, slot->not_available, i); */
270       pthread_mutex_unlock(&slot->lock);
271    }
272 
273    return select_id;
274 }
275 
276 /*===========================================================================
277 
278 FUNCTION    loc_unlock_slot
279 
280 DESCRIPTION
281    Unlocks a buffer slot
282 
283 DEPENDENCIES
284    N/A
285 
286 RETURN VALUE
287    None
288 
289 SIDE EFFECTS
290    N/A
291 
292 ===========================================================================*/
loc_unlock_slot(int select_id)293 static void loc_unlock_slot(int select_id)
294 {
295    pthread_mutex_unlock(&loc_sync_data.slots[select_id].lock);
296 }
297 
298 /*===========================================================================
299 
300 FUNCTION    loc_lock_slot
301 
302 DESCRIPTION
303    Locks a specific slot that was previously locked from loc_lock_a_slot
304 
305 DEPENDENCIES
306    N/A
307 
308 RETURN VALUE
309    None
310 
311 SIDE EFFECTS
312    N/A
313 
314 ===========================================================================*/
loc_lock_slot(int select_id)315 static void loc_lock_slot(int select_id)
316 {
317     pthread_mutex_lock(&loc_sync_data.slots[select_id].lock);
318 }
319 
320 /*===========================================================================
321 
322 FUNCTION    loc_set_slot_in_use
323 
324 DESCRIPTION
325    Sets the in_use flag of slot to true or false.
326    Should be called only after the slot is locked
327 
328 DEPENDENCIES
329    N/A
330 
331 RETURN VALUE
332    None
333 
334 SIDE EFFECTS
335    N/A
336 
337 ===========================================================================*/
loc_set_slot_in_use(int select_id,boolean in_use)338 static void loc_set_slot_in_use(int select_id, boolean in_use)
339 {
340     loc_sync_data.slots[select_id].in_use = in_use;
341     if (in_use == 1)
342         loc_sync_data.slots[select_id].signal_sent = 0;
343 }
344 
345 /*===========================================================================
346 
347 FUNCTION    loc_api_save_callback
348 
349 DESCRIPTION
350    Selects which callback or IOCTL event to wait for.
351 
352    The event_mask specifies the event(s). If it is RPC_LOC_EVENT_IOCTL_REPORT,
353    then ioctl_type specifies the IOCTL event.
354 
355    If ioctl_type is non-zero, RPC_LOC_EVENT_IOCTL_REPORT is automatically added.
356 
357 DEPENDENCIES
358    N/A
359 
360 RETURN VALUE
361    Select ID (>=0)     : successful
362    -1                  : out of buffer
363 
364 SIDE EFFECTS
365    N/A
366 
367 ===========================================================================*/
loc_api_save_callback(int select_id,rpc_loc_client_handle_type loc_handle,rpc_loc_event_mask_type event_mask,rpc_loc_ioctl_e_type ioctl_type)368 static void loc_api_save_callback(
369       int                              select_id,            /* Selected slot */
370       rpc_loc_client_handle_type       loc_handle,           /* Client handle */
371       rpc_loc_event_mask_type          event_mask,           /* Event mask to wait for */
372       rpc_loc_ioctl_e_type             ioctl_type            /* IOCTL type to wait for */
373 )
374 {
375    loc_sync_call_slot_s_type *slot = &loc_sync_data.slots[select_id];
376 
377    slot->loc_handle = loc_handle;
378 
379    slot->loc_cb_wait_event_mask = event_mask;
380    slot->ioctl_type = ioctl_type;
381    if (ioctl_type) slot->loc_cb_wait_event_mask |= RPC_LOC_EVENT_IOCTL_REPORT;
382 
383    return;
384 }
385 
386 /*===========================================================================
387 
388 FUNCTION    loc_save_user_payload
389 
390 DESCRIPTION
391    Saves received payload into user data structures
392 
393 RETURN VALUE
394    None
395 
396 ===========================================================================*/
loc_save_user_payload(rpc_loc_event_payload_u_type * user_cb_payload,rpc_loc_ioctl_callback_s_type * user_ioctl_buffer,const rpc_loc_event_payload_u_type * received_cb_payload)397 static void loc_save_user_payload(
398       rpc_loc_event_payload_u_type  *user_cb_payload,
399       rpc_loc_ioctl_callback_s_type *user_ioctl_buffer,
400       const rpc_loc_event_payload_u_type  *received_cb_payload
401 )
402 {
403    if (user_cb_payload)
404    {
405       memcpy(user_cb_payload, received_cb_payload,
406             sizeof (rpc_loc_event_payload_u_type));
407    }
408    if (user_ioctl_buffer)
409    {
410       memcpy(user_ioctl_buffer,
411             &received_cb_payload->rpc_loc_event_payload_u_type_u.ioctl_report,
412             sizeof *user_ioctl_buffer);
413    }
414 }
415 
416 /*===========================================================================
417 
418 FUNCTION    loc_api_wait_callback
419 
420 DESCRIPTION
421    Waits for a selected callback. The wait expires in timeout_seconds seconds.
422 
423    If the function is called before an existing wait has finished, it will
424    immediately return EBUSY.
425 
426 DEPENDENCIES
427    N/A
428 
429 RETURN VALUE
430    RPC_LOC_API_SUCCESS              if successful (0)
431    RPC_LOC_API_TIMEOUT              if timed out
432    RPC_LOC_API_ENGINE_BUSY          if already in a wait
433    RPC_LOC_API_INVALID_PARAMETER    if callback is not yet selected
434 
435 SIDE EFFECTS
436    N/A
437 
438 ===========================================================================*/
loc_api_wait_callback(int select_id,int timeout_seconds,rpc_loc_event_payload_u_type * callback_payload,rpc_loc_ioctl_callback_s_type * ioctl_payload)439 static int loc_api_wait_callback(
440       int select_id,        /* ID from loc_select_callback() */
441       int timeout_seconds,  /* Timeout in this number of seconds  */
442       rpc_loc_event_payload_u_type     *callback_payload,    /* Pointer to callback payload buffer, can be NULL */
443       rpc_loc_ioctl_callback_s_type    *ioctl_payload        /* Pointer to IOCTL payload, can be NULL */
444 )
445 {
446    int ret_val = RPC_LOC_API_SUCCESS;  /* the return value of this function: 0 = no error */
447    int rc = 0;                         /* return code from pthread calls */
448 
449    struct timespec expire_time;
450 
451    loc_sync_call_slot_s_type *slot = &loc_sync_data.slots[select_id];
452 
453    clock_gettime(CLOCK_REALTIME, &expire_time);
454    expire_time.tv_sec += timeout_seconds;
455 
456    /* Waiting */
457    while (slot->signal_sent == 0 && rc != ETIMEDOUT) {
458        rc = pthread_cond_timedwait(&slot->loc_cb_arrived_cond,
459              &slot->lock, &expire_time);
460    }
461 
462    if (rc == ETIMEDOUT)
463    {
464       ret_val = RPC_LOC_API_TIMEOUT; /* Timed out */
465       ALOGE("TIMEOUT: %d", select_id);
466    }
467    else {
468       /* Obtained the first awaited callback */
469       ret_val = RPC_LOC_API_SUCCESS;       /* Successful */
470       loc_save_user_payload(callback_payload, ioctl_payload, &slot->loc_cb_received_payload);
471    }
472 
473    return ret_val;
474 }
475 
476 /*===========================================================================
477 
478 FUNCTION    loc_api_sync_ioctl
479 
480 DESCRIPTION
481    Synchronous IOCTL call (reentrant version)
482 
483 DEPENDENCIES
484    N/A
485 
486 RETURN VALUE
487    Loc API error code (0 = success)
488 
489 SIDE EFFECTS
490    N/A
491 
492 ===========================================================================*/
loc_api_sync_ioctl(rpc_loc_client_handle_type handle,rpc_loc_ioctl_e_type ioctl_type,rpc_loc_ioctl_data_u_type * ioctl_data_ptr,uint32 timeout_msec,rpc_loc_ioctl_callback_s_type * cb_data_ptr)493 int loc_api_sync_ioctl
494 (
495       rpc_loc_client_handle_type           handle,
496       rpc_loc_ioctl_e_type                 ioctl_type,
497       rpc_loc_ioctl_data_u_type*           ioctl_data_ptr,
498       uint32                               timeout_msec,
499       rpc_loc_ioctl_callback_s_type       *cb_data_ptr
500 )
501 {
502    int                              rc = -1;
503    int                              select_id;
504    rpc_loc_ioctl_callback_s_type    callback_data;
505 
506    select_id = loc_lock_a_slot();
507 
508    if (select_id < 0 || select_id >= loc_sync_data.num_of_slots)
509    {
510       ALOGE("slot not available ioctl_type = %s",
511            loc_get_ioctl_type_name(ioctl_type));
512       return rc;
513    }
514 
515    loc_set_slot_in_use(select_id, 1); // set slot in use to true
516 
517    // Select the callback we are waiting for
518    loc_api_save_callback(select_id, handle, 0, ioctl_type);
519 
520    loc_unlock_slot(select_id); // slot is unlocked, but in_use is still true
521 
522    // we want to avoid keeping the slot locked during the loc_ioctl because the rpc
523    // framework will also lock a different mutex during this call, and typically
524    // locking two different mutexes at the same time can lead to deadlock.
525    rc =  loc_ioctl(handle, ioctl_type, ioctl_data_ptr);
526 
527    loc_lock_slot(select_id);
528 
529    if (rc != RPC_LOC_API_SUCCESS)
530    {
531       ALOGE("loc_ioctl failed select_id = %d, ioctl_type %s, returned %s",
532            select_id, loc_get_ioctl_type_name(ioctl_type), loc_get_ioctl_status_name(rc));
533    }
534    else {
535       ALOGV("select_id = %d, ioctl_type %d, returned RPC_LOC_API_SUCCESS",
536           select_id, ioctl_type);
537       // Wait for the callback of loc_ioctl
538       if ((rc = loc_api_wait_callback(select_id, timeout_msec / 1000, NULL, &callback_data)) != 0)
539       {
540          // Callback waiting failed
541          ALOGE("callback wait failed select_id = %d, ioctl_type %s, returned %s",
542               select_id, loc_get_ioctl_type_name(ioctl_type), loc_get_ioctl_status_name(rc));
543       }
544       else
545       {
546          if (cb_data_ptr) memcpy(cb_data_ptr, &callback_data, sizeof *cb_data_ptr);
547          if (callback_data.status != RPC_LOC_API_SUCCESS)
548          {
549             rc = callback_data.status;
550             ALOGE("callback status failed select_id = %d, ioctl_type %s, returned %s",
551                  select_id, loc_get_ioctl_type_name(ioctl_type), loc_get_ioctl_status_name(rc));
552          } else {
553             ALOGV("callback status success select_id = %d, ioctl_type %d, returned %d",
554                 select_id, ioctl_type, rc);
555          }
556       } /* wait callback */
557    } /* loc_ioctl */
558 
559    loc_set_slot_in_use(select_id, 0); // set slot in use to false
560    loc_unlock_slot(select_id);
561 
562    return rc;
563 }
564 
565 
566