1 /*
2  * Copyright 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 
17 #ifndef UTILITY_HANDLE_TRACKER_H
18 #define UTILITY_HANDLE_TRACKER_H
19 
20 #include <stdint.h>
21 #include <utils/Mutex.h>
22 
23 typedef int32_t  aaudio_handle_t;
24 typedef int32_t  handle_tracker_type_t;       // what kind of handle
25 typedef int32_t  handle_tracker_slot_t;       // index in allocation table
26 typedef int32_t  handle_tracker_generation_t; // incremented when slot used
27 typedef uint16_t handle_tracker_header_t;     // combines type and generation
28 typedef void    *handle_tracker_address_t;    // address of something that is stored here
29 
30 #define HANDLE_TRACKER_MAX_TYPES    (1 << 3)
31 #define HANDLE_TRACKER_MAX_HANDLES  (1 << 16)
32 
33 /**
34  * Represent Objects using an integer handle that can be used with Java.
35  * This also makes the 'C' ABI more robust.
36  *
37  * Note that this should only be called from a single thread.
38  * If you call it from more than one thread then you need to use your own mutex.
39  */
40 class HandleTracker {
41 
42 public:
43     /**
44      * @param maxHandles cannot exceed HANDLE_TRACKER_MAX_HANDLES
45      */
46     HandleTracker(uint32_t maxHandles = 256);
47     virtual ~HandleTracker();
48 
49     /**
50      * Don't use if this returns false;
51      * @return true if the internal allocation succeeded
52      */
53     bool isInitialized() const;
54 
55     /**
56      * Store a pointer and return a handle that can be used to retrieve the pointer.
57      *
58      * It is safe to call put() or remove() from multiple threads.
59      *
60      * @param expectedType the type of the object to be tracked
61      * @param address pointer to be converted to a handle
62      * @return a valid handle or a negative error
63      */
64     aaudio_handle_t put(handle_tracker_type_t expectedType, handle_tracker_address_t address);
65 
66     /**
67      * Get the original pointer associated with the handle.
68      * The handle will be validated to prevent stale handles from being reused.
69      * Note that the validation is designed to prevent common coding errors and not
70      * to prevent deliberate hacking.
71      *
72      * @param expectedType shouldmatch the type we passed to put()
73      * @param handle to be converted to a pointer
74      * @return address associated with handle or nullptr
75      */
76     handle_tracker_address_t get(handle_tracker_type_t expectedType, aaudio_handle_t handle) const;
77 
78     /**
79      * Free up the storage associated with the handle.
80      * Subsequent attempts to use the handle will fail.
81      *
82      * Do NOT remove() a handle while get() is being called for the same handle from another thread.
83      *
84      * @param expectedType shouldmatch the type we passed to put()
85      * @param handle to be removed from tracking
86      * @return address associated with handle or nullptr if not found
87      */
88     handle_tracker_address_t remove(handle_tracker_type_t expectedType, aaudio_handle_t handle);
89 
90 private:
91     const int32_t               mMaxHandleCount;   // size of array
92     // This address is const after initialization.
93     handle_tracker_address_t  * mHandleAddresses;  // address of objects or a free linked list node
94     // This address is const after initialization.
95     handle_tracker_header_t   * mHandleHeaders;    // combination of type and generation
96     // head of the linked list of free nodes in mHandleAddresses
97     handle_tracker_address_t  * mNextFreeAddress;
98 
99     // This Mutex protects the linked list of free nodes.
100     // The list is managed using mHandleAddresses and mNextFreeAddress.
101     // The data in mHandleHeaders is only changed by put() and remove().
102     android::Mutex              mLock;
103 
104     /**
105      * Pull slot off of a list of empty slots.
106      * @return index or a negative error
107      */
108     handle_tracker_slot_t allocateSlot_l();
109 
110     /**
111      * Increment the generation for the slot, avoiding zero.
112      */
113     handle_tracker_generation_t nextGeneration_l(handle_tracker_slot_t index);
114 
115     /**
116      * Validate the handle and return the corresponding index.
117      * @return slot index or a negative error
118      */
119     handle_tracker_slot_t handleToIndex(aaudio_handle_t handle, handle_tracker_type_t type) const;
120 
121     /**
122      * Construct a handle from a header and an index.
123      * @param header combination of a type and a generation
124      * @param index slot index returned from allocateSlot
125      * @return handle or a negative error
126      */
127     static aaudio_handle_t buildHandle(handle_tracker_header_t header, handle_tracker_slot_t index);
128 
129     /**
130      * Combine a type and a generation field into a header.
131      */
132     static handle_tracker_header_t buildHeader(handle_tracker_type_t type,
133                 handle_tracker_generation_t generation);
134 
135     /**
136      * Extract the index from a handle.
137      * Does not validate the handle.
138      * @return index associated with a handle
139      */
140     static handle_tracker_slot_t extractIndex(aaudio_handle_t handle);
141 
142     /**
143      * Extract the generation from a handle.
144      * Does not validate the handle.
145      * @return generation associated with a handle
146      */
147     static handle_tracker_generation_t extractGeneration(aaudio_handle_t handle);
148 
149 };
150 
151 #endif //UTILITY_HANDLE_TRACKER_H
152