xref: /aosp_15_r20/frameworks/wilhelm/src/itf/IDynamicInterfaceManagement.cpp (revision bebae9c0e76121f8312ccb50385c080b3a0b023c)
1*bebae9c0SAndroid Build Coastguard Worker /*
2*bebae9c0SAndroid Build Coastguard Worker  * Copyright (C) 2010 The Android Open Source Project
3*bebae9c0SAndroid Build Coastguard Worker  *
4*bebae9c0SAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*bebae9c0SAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*bebae9c0SAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*bebae9c0SAndroid Build Coastguard Worker  *
8*bebae9c0SAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*bebae9c0SAndroid Build Coastguard Worker  *
10*bebae9c0SAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*bebae9c0SAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*bebae9c0SAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*bebae9c0SAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*bebae9c0SAndroid Build Coastguard Worker  * limitations under the License.
15*bebae9c0SAndroid Build Coastguard Worker  */
16*bebae9c0SAndroid Build Coastguard Worker 
17*bebae9c0SAndroid Build Coastguard Worker /* DynamicInterfaceManagement implementation */
18*bebae9c0SAndroid Build Coastguard Worker 
19*bebae9c0SAndroid Build Coastguard Worker #include "sles_allinclusive.h"
20*bebae9c0SAndroid Build Coastguard Worker 
21*bebae9c0SAndroid Build Coastguard Worker 
22*bebae9c0SAndroid Build Coastguard Worker // Called by a worker thread to handle an asynchronous AddInterface.
23*bebae9c0SAndroid Build Coastguard Worker // Parameter self is the DynamicInterface, and MPH specifies which interface to add.
24*bebae9c0SAndroid Build Coastguard Worker 
HandleAdd(void * self,void * ignored,int MPH)25*bebae9c0SAndroid Build Coastguard Worker static void HandleAdd(void *self, void *ignored, int MPH)
26*bebae9c0SAndroid Build Coastguard Worker {
27*bebae9c0SAndroid Build Coastguard Worker 
28*bebae9c0SAndroid Build Coastguard Worker     // validate input parameters
29*bebae9c0SAndroid Build Coastguard Worker     IDynamicInterfaceManagement *thiz = (IDynamicInterfaceManagement *) self;
30*bebae9c0SAndroid Build Coastguard Worker     assert(NULL != thiz);
31*bebae9c0SAndroid Build Coastguard Worker     IObject *thisObject = InterfaceToIObject(thiz);
32*bebae9c0SAndroid Build Coastguard Worker     assert(NULL != thisObject);
33*bebae9c0SAndroid Build Coastguard Worker     assert(0 <= MPH && MPH < MPH_MAX);
34*bebae9c0SAndroid Build Coastguard Worker     const ClassTable *clazz = thisObject->mClass;
35*bebae9c0SAndroid Build Coastguard Worker     assert(NULL != clazz);
36*bebae9c0SAndroid Build Coastguard Worker     int index = clazz->mMPH_to_index[MPH];
37*bebae9c0SAndroid Build Coastguard Worker     assert(0 <= index && index < (int) clazz->mInterfaceCount);
38*bebae9c0SAndroid Build Coastguard Worker     SLuint8 *interfaceStateP = &thisObject->mInterfaceStates[index];
39*bebae9c0SAndroid Build Coastguard Worker     SLresult result;
40*bebae9c0SAndroid Build Coastguard Worker 
41*bebae9c0SAndroid Build Coastguard Worker     // check interface state
42*bebae9c0SAndroid Build Coastguard Worker     object_lock_exclusive(thisObject);
43*bebae9c0SAndroid Build Coastguard Worker     SLuint8 state = *interfaceStateP;
44*bebae9c0SAndroid Build Coastguard Worker     switch (state) {
45*bebae9c0SAndroid Build Coastguard Worker 
46*bebae9c0SAndroid Build Coastguard Worker     case INTERFACE_ADDING_1:    // normal case
47*bebae9c0SAndroid Build Coastguard Worker         {
48*bebae9c0SAndroid Build Coastguard Worker         // change state to indicate we are now adding the interface
49*bebae9c0SAndroid Build Coastguard Worker         *interfaceStateP = INTERFACE_ADDING_2;
50*bebae9c0SAndroid Build Coastguard Worker         object_unlock_exclusive(thisObject);
51*bebae9c0SAndroid Build Coastguard Worker 
52*bebae9c0SAndroid Build Coastguard Worker         // this section runs with mutex unlocked
53*bebae9c0SAndroid Build Coastguard Worker         const struct iid_vtable *x = &clazz->mInterfaces[index];
54*bebae9c0SAndroid Build Coastguard Worker         size_t offset = x->mOffset;
55*bebae9c0SAndroid Build Coastguard Worker         void *thisItf = (char *) thisObject + offset;
56*bebae9c0SAndroid Build Coastguard Worker         BoolHook expose = MPH_init_table[MPH].mExpose;
57*bebae9c0SAndroid Build Coastguard Worker         // call the optional expose hook
58*bebae9c0SAndroid Build Coastguard Worker         if ((NULL == expose) || (*expose)(thisItf)) {
59*bebae9c0SAndroid Build Coastguard Worker             result = SL_RESULT_SUCCESS;
60*bebae9c0SAndroid Build Coastguard Worker         } else {
61*bebae9c0SAndroid Build Coastguard Worker             result = SL_RESULT_FEATURE_UNSUPPORTED;
62*bebae9c0SAndroid Build Coastguard Worker         }
63*bebae9c0SAndroid Build Coastguard Worker 
64*bebae9c0SAndroid Build Coastguard Worker         // re-lock mutex to update state
65*bebae9c0SAndroid Build Coastguard Worker         object_lock_exclusive(thisObject);
66*bebae9c0SAndroid Build Coastguard Worker         assert(INTERFACE_ADDING_2 == *interfaceStateP);
67*bebae9c0SAndroid Build Coastguard Worker         if (SL_RESULT_SUCCESS == result) {
68*bebae9c0SAndroid Build Coastguard Worker             ((size_t *) thisItf)[0] ^= ~0;
69*bebae9c0SAndroid Build Coastguard Worker             state = INTERFACE_ADDED;
70*bebae9c0SAndroid Build Coastguard Worker         } else {
71*bebae9c0SAndroid Build Coastguard Worker             state = INTERFACE_INITIALIZED;
72*bebae9c0SAndroid Build Coastguard Worker         }
73*bebae9c0SAndroid Build Coastguard Worker         }
74*bebae9c0SAndroid Build Coastguard Worker         break;
75*bebae9c0SAndroid Build Coastguard Worker 
76*bebae9c0SAndroid Build Coastguard Worker     case INTERFACE_ADDING_1A:   // operation was aborted while on work queue
77*bebae9c0SAndroid Build Coastguard Worker         result = SL_RESULT_OPERATION_ABORTED;
78*bebae9c0SAndroid Build Coastguard Worker         state = INTERFACE_INITIALIZED;
79*bebae9c0SAndroid Build Coastguard Worker         break;
80*bebae9c0SAndroid Build Coastguard Worker 
81*bebae9c0SAndroid Build Coastguard Worker     default:                    // impossible
82*bebae9c0SAndroid Build Coastguard Worker         assert(SL_BOOLEAN_FALSE);
83*bebae9c0SAndroid Build Coastguard Worker         result = SL_RESULT_INTERNAL_ERROR;
84*bebae9c0SAndroid Build Coastguard Worker         break;
85*bebae9c0SAndroid Build Coastguard Worker 
86*bebae9c0SAndroid Build Coastguard Worker     }
87*bebae9c0SAndroid Build Coastguard Worker 
88*bebae9c0SAndroid Build Coastguard Worker     // mutex is locked, update state
89*bebae9c0SAndroid Build Coastguard Worker     *interfaceStateP = state;
90*bebae9c0SAndroid Build Coastguard Worker 
91*bebae9c0SAndroid Build Coastguard Worker     // Make a copy of these, so we can call the callback with mutex unlocked
92*bebae9c0SAndroid Build Coastguard Worker     slDynamicInterfaceManagementCallback callback = thiz->mCallback;
93*bebae9c0SAndroid Build Coastguard Worker     void *context = thiz->mContext;
94*bebae9c0SAndroid Build Coastguard Worker     object_unlock_exclusive(thisObject);
95*bebae9c0SAndroid Build Coastguard Worker 
96*bebae9c0SAndroid Build Coastguard Worker     // Note that the mutex is unlocked during the callback
97*bebae9c0SAndroid Build Coastguard Worker     if (NULL != callback) {
98*bebae9c0SAndroid Build Coastguard Worker         const SLInterfaceID iid = &SL_IID_array[MPH]; // equal but not == to the original IID
99*bebae9c0SAndroid Build Coastguard Worker         (*callback)(&thiz->mItf, context, SL_DYNAMIC_ITF_EVENT_ASYNC_TERMINATION, result, iid);
100*bebae9c0SAndroid Build Coastguard Worker     }
101*bebae9c0SAndroid Build Coastguard Worker 
102*bebae9c0SAndroid Build Coastguard Worker }
103*bebae9c0SAndroid Build Coastguard Worker 
104*bebae9c0SAndroid Build Coastguard Worker 
IDynamicInterfaceManagement_AddInterface(SLDynamicInterfaceManagementItf self,const SLInterfaceID iid,SLboolean async)105*bebae9c0SAndroid Build Coastguard Worker static SLresult IDynamicInterfaceManagement_AddInterface(SLDynamicInterfaceManagementItf self,
106*bebae9c0SAndroid Build Coastguard Worker     const SLInterfaceID iid, SLboolean async)
107*bebae9c0SAndroid Build Coastguard Worker {
108*bebae9c0SAndroid Build Coastguard Worker     SL_ENTER_INTERFACE
109*bebae9c0SAndroid Build Coastguard Worker 
110*bebae9c0SAndroid Build Coastguard Worker     // validate input parameters
111*bebae9c0SAndroid Build Coastguard Worker     if (NULL == iid) {
112*bebae9c0SAndroid Build Coastguard Worker         result = SL_RESULT_PARAMETER_INVALID;
113*bebae9c0SAndroid Build Coastguard Worker     } else {
114*bebae9c0SAndroid Build Coastguard Worker         IDynamicInterfaceManagement *thiz = (IDynamicInterfaceManagement *) self;
115*bebae9c0SAndroid Build Coastguard Worker         IObject *thisObject = InterfaceToIObject(thiz);
116*bebae9c0SAndroid Build Coastguard Worker         const ClassTable *clazz = thisObject->mClass;
117*bebae9c0SAndroid Build Coastguard Worker         int MPH, index;
118*bebae9c0SAndroid Build Coastguard Worker         if ((0 > (MPH = IID_to_MPH(iid))) ||
119*bebae9c0SAndroid Build Coastguard Worker                 // no need to check for an initialization hook
120*bebae9c0SAndroid Build Coastguard Worker                 // (NULL == MPH_init_table[MPH].mInit) ||
121*bebae9c0SAndroid Build Coastguard Worker                 (0 > (index = clazz->mMPH_to_index[MPH]))) {
122*bebae9c0SAndroid Build Coastguard Worker             result = SL_RESULT_FEATURE_UNSUPPORTED;
123*bebae9c0SAndroid Build Coastguard Worker         } else {
124*bebae9c0SAndroid Build Coastguard Worker             assert(index < (int) clazz->mInterfaceCount);
125*bebae9c0SAndroid Build Coastguard Worker             SLuint8 *interfaceStateP = &thisObject->mInterfaceStates[index];
126*bebae9c0SAndroid Build Coastguard Worker 
127*bebae9c0SAndroid Build Coastguard Worker             // check interface state
128*bebae9c0SAndroid Build Coastguard Worker             object_lock_exclusive(thisObject);
129*bebae9c0SAndroid Build Coastguard Worker             switch (*interfaceStateP) {
130*bebae9c0SAndroid Build Coastguard Worker 
131*bebae9c0SAndroid Build Coastguard Worker             case INTERFACE_INITIALIZED: // normal case
132*bebae9c0SAndroid Build Coastguard Worker                 if (async) {
133*bebae9c0SAndroid Build Coastguard Worker                     // Asynchronous: mark operation pending and cancellable
134*bebae9c0SAndroid Build Coastguard Worker                     *interfaceStateP = INTERFACE_ADDING_1;
135*bebae9c0SAndroid Build Coastguard Worker                     object_unlock_exclusive(thisObject);
136*bebae9c0SAndroid Build Coastguard Worker 
137*bebae9c0SAndroid Build Coastguard Worker                     // this section runs with mutex unlocked
138*bebae9c0SAndroid Build Coastguard Worker                     result = ThreadPool_add_ppi(&thisObject->mEngine->mThreadPool, HandleAdd, thiz,
139*bebae9c0SAndroid Build Coastguard Worker                         NULL, MPH);
140*bebae9c0SAndroid Build Coastguard Worker                     if (SL_RESULT_SUCCESS != result) {
141*bebae9c0SAndroid Build Coastguard Worker                         // Engine was destroyed during add, or insufficient memory,
142*bebae9c0SAndroid Build Coastguard Worker                         // so restore mInterfaceStates state to prior value
143*bebae9c0SAndroid Build Coastguard Worker                         object_lock_exclusive(thisObject);
144*bebae9c0SAndroid Build Coastguard Worker                         switch (*interfaceStateP) {
145*bebae9c0SAndroid Build Coastguard Worker                         case INTERFACE_ADDING_1:    // normal
146*bebae9c0SAndroid Build Coastguard Worker                         case INTERFACE_ADDING_1A:   // operation aborted while mutex unlocked
147*bebae9c0SAndroid Build Coastguard Worker                             *interfaceStateP = INTERFACE_INITIALIZED;
148*bebae9c0SAndroid Build Coastguard Worker                             break;
149*bebae9c0SAndroid Build Coastguard Worker                         default:                    // unexpected
150*bebae9c0SAndroid Build Coastguard Worker                             // leave state alone
151*bebae9c0SAndroid Build Coastguard Worker                             break;
152*bebae9c0SAndroid Build Coastguard Worker                         }
153*bebae9c0SAndroid Build Coastguard Worker                     }
154*bebae9c0SAndroid Build Coastguard Worker 
155*bebae9c0SAndroid Build Coastguard Worker                 } else {
156*bebae9c0SAndroid Build Coastguard Worker                     // Synchronous: mark operation pending to prevent duplication
157*bebae9c0SAndroid Build Coastguard Worker                     *interfaceStateP = INTERFACE_ADDING_2;
158*bebae9c0SAndroid Build Coastguard Worker                     object_unlock_exclusive(thisObject);
159*bebae9c0SAndroid Build Coastguard Worker 
160*bebae9c0SAndroid Build Coastguard Worker                     // this section runs with mutex unlocked
161*bebae9c0SAndroid Build Coastguard Worker                     const struct iid_vtable *x = &clazz->mInterfaces[index];
162*bebae9c0SAndroid Build Coastguard Worker                     size_t offset = x->mOffset;
163*bebae9c0SAndroid Build Coastguard Worker                     void *thisItf = (char *) thisObject + offset;
164*bebae9c0SAndroid Build Coastguard Worker                     // call the optional expose hook
165*bebae9c0SAndroid Build Coastguard Worker                     BoolHook expose = MPH_init_table[MPH].mExpose;
166*bebae9c0SAndroid Build Coastguard Worker                     if ((NULL == expose) || (*expose)(thisItf)) {
167*bebae9c0SAndroid Build Coastguard Worker                         result = SL_RESULT_SUCCESS;
168*bebae9c0SAndroid Build Coastguard Worker                     } else {
169*bebae9c0SAndroid Build Coastguard Worker                         result = SL_RESULT_FEATURE_UNSUPPORTED;
170*bebae9c0SAndroid Build Coastguard Worker                     }
171*bebae9c0SAndroid Build Coastguard Worker 
172*bebae9c0SAndroid Build Coastguard Worker                     // re-lock mutex to update state
173*bebae9c0SAndroid Build Coastguard Worker                     object_lock_exclusive(thisObject);
174*bebae9c0SAndroid Build Coastguard Worker                     assert(INTERFACE_ADDING_2 == *interfaceStateP);
175*bebae9c0SAndroid Build Coastguard Worker                     if (SL_RESULT_SUCCESS == result) {
176*bebae9c0SAndroid Build Coastguard Worker                         *interfaceStateP = INTERFACE_ADDED;
177*bebae9c0SAndroid Build Coastguard Worker                     } else {
178*bebae9c0SAndroid Build Coastguard Worker                         *interfaceStateP = INTERFACE_INITIALIZED;
179*bebae9c0SAndroid Build Coastguard Worker                     }
180*bebae9c0SAndroid Build Coastguard Worker                 }
181*bebae9c0SAndroid Build Coastguard Worker 
182*bebae9c0SAndroid Build Coastguard Worker                 // mutex is still locked
183*bebae9c0SAndroid Build Coastguard Worker                 break;
184*bebae9c0SAndroid Build Coastguard Worker 
185*bebae9c0SAndroid Build Coastguard Worker             default:    // disallow adding of (partially) initialized interfaces
186*bebae9c0SAndroid Build Coastguard Worker                 result = SL_RESULT_PRECONDITIONS_VIOLATED;
187*bebae9c0SAndroid Build Coastguard Worker                 break;
188*bebae9c0SAndroid Build Coastguard Worker 
189*bebae9c0SAndroid Build Coastguard Worker             }
190*bebae9c0SAndroid Build Coastguard Worker 
191*bebae9c0SAndroid Build Coastguard Worker             object_unlock_exclusive(thisObject);
192*bebae9c0SAndroid Build Coastguard Worker 
193*bebae9c0SAndroid Build Coastguard Worker         }
194*bebae9c0SAndroid Build Coastguard Worker     }
195*bebae9c0SAndroid Build Coastguard Worker 
196*bebae9c0SAndroid Build Coastguard Worker     SL_LEAVE_INTERFACE
197*bebae9c0SAndroid Build Coastguard Worker }
198*bebae9c0SAndroid Build Coastguard Worker 
199*bebae9c0SAndroid Build Coastguard Worker 
IDynamicInterfaceManagement_RemoveInterface(SLDynamicInterfaceManagementItf self,const SLInterfaceID iid)200*bebae9c0SAndroid Build Coastguard Worker static SLresult IDynamicInterfaceManagement_RemoveInterface(
201*bebae9c0SAndroid Build Coastguard Worker     SLDynamicInterfaceManagementItf self, const SLInterfaceID iid)
202*bebae9c0SAndroid Build Coastguard Worker {
203*bebae9c0SAndroid Build Coastguard Worker     SL_ENTER_INTERFACE
204*bebae9c0SAndroid Build Coastguard Worker 
205*bebae9c0SAndroid Build Coastguard Worker #if USE_PROFILES & USE_PROFILES_BASE
206*bebae9c0SAndroid Build Coastguard Worker     // validate input parameters
207*bebae9c0SAndroid Build Coastguard Worker     if (NULL == iid) {
208*bebae9c0SAndroid Build Coastguard Worker         result = SL_RESULT_PARAMETER_INVALID;
209*bebae9c0SAndroid Build Coastguard Worker     } else {
210*bebae9c0SAndroid Build Coastguard Worker         IDynamicInterfaceManagement *thiz = (IDynamicInterfaceManagement *) self;
211*bebae9c0SAndroid Build Coastguard Worker         IObject *thisObject = InterfaceToIObject(thiz);
212*bebae9c0SAndroid Build Coastguard Worker         const ClassTable *clazz = thisObject->mClass;
213*bebae9c0SAndroid Build Coastguard Worker         int MPH, index;
214*bebae9c0SAndroid Build Coastguard Worker         if ((0 > (MPH = IID_to_MPH(iid))) ||
215*bebae9c0SAndroid Build Coastguard Worker                 // no need to check for an initialization hook
216*bebae9c0SAndroid Build Coastguard Worker                 // (NULL == MPH_init_table[MPH].mInit) ||
217*bebae9c0SAndroid Build Coastguard Worker                 (0 > (index = clazz->mMPH_to_index[MPH]))) {
218*bebae9c0SAndroid Build Coastguard Worker             result = SL_RESULT_PRECONDITIONS_VIOLATED;
219*bebae9c0SAndroid Build Coastguard Worker         } else {
220*bebae9c0SAndroid Build Coastguard Worker             SLuint8 *interfaceStateP = &thisObject->mInterfaceStates[index];
221*bebae9c0SAndroid Build Coastguard Worker 
222*bebae9c0SAndroid Build Coastguard Worker             // check interface state
223*bebae9c0SAndroid Build Coastguard Worker             object_lock_exclusive(thisObject);
224*bebae9c0SAndroid Build Coastguard Worker             switch (*interfaceStateP) {
225*bebae9c0SAndroid Build Coastguard Worker 
226*bebae9c0SAndroid Build Coastguard Worker             case INTERFACE_ADDED:       // normal cases
227*bebae9c0SAndroid Build Coastguard Worker             case INTERFACE_SUSPENDED:
228*bebae9c0SAndroid Build Coastguard Worker                 {
229*bebae9c0SAndroid Build Coastguard Worker                 // Compute address of the interface
230*bebae9c0SAndroid Build Coastguard Worker                 const struct iid_vtable *x = &clazz->mInterfaces[index];
231*bebae9c0SAndroid Build Coastguard Worker                 size_t offset = x->mOffset;
232*bebae9c0SAndroid Build Coastguard Worker                 void *thisItf = (char *) thisObject + offset;
233*bebae9c0SAndroid Build Coastguard Worker 
234*bebae9c0SAndroid Build Coastguard Worker                 // Mark operation pending (not necessary; remove is synchronous with mutex locked)
235*bebae9c0SAndroid Build Coastguard Worker                 *interfaceStateP = INTERFACE_REMOVING;
236*bebae9c0SAndroid Build Coastguard Worker 
237*bebae9c0SAndroid Build Coastguard Worker                 // Check if application ever called Object::GetInterface
238*bebae9c0SAndroid Build Coastguard Worker                 unsigned mask = 1 << index;
239*bebae9c0SAndroid Build Coastguard Worker                 if (thisObject->mGottenMask & mask) {
240*bebae9c0SAndroid Build Coastguard Worker                     thisObject->mGottenMask &= ~mask;
241*bebae9c0SAndroid Build Coastguard Worker                     // This trickery invalidates the v-table
242*bebae9c0SAndroid Build Coastguard Worker                     ((size_t *) thisItf)[0] ^= ~0;
243*bebae9c0SAndroid Build Coastguard Worker                 }
244*bebae9c0SAndroid Build Coastguard Worker 
245*bebae9c0SAndroid Build Coastguard Worker                 // The remove hook is called with mutex locked
246*bebae9c0SAndroid Build Coastguard Worker                 VoidHook remove = MPH_init_table[MPH].mRemove;
247*bebae9c0SAndroid Build Coastguard Worker                 if (NULL != remove) {
248*bebae9c0SAndroid Build Coastguard Worker                     (*remove)(thisItf);
249*bebae9c0SAndroid Build Coastguard Worker                 }
250*bebae9c0SAndroid Build Coastguard Worker                 result = SL_RESULT_SUCCESS;
251*bebae9c0SAndroid Build Coastguard Worker 
252*bebae9c0SAndroid Build Coastguard Worker                 assert(INTERFACE_REMOVING == *interfaceStateP);
253*bebae9c0SAndroid Build Coastguard Worker                 *interfaceStateP = INTERFACE_INITIALIZED;
254*bebae9c0SAndroid Build Coastguard Worker                 }
255*bebae9c0SAndroid Build Coastguard Worker 
256*bebae9c0SAndroid Build Coastguard Worker                 // mutex is still locked
257*bebae9c0SAndroid Build Coastguard Worker                 break;
258*bebae9c0SAndroid Build Coastguard Worker 
259*bebae9c0SAndroid Build Coastguard Worker             default:
260*bebae9c0SAndroid Build Coastguard Worker                 // disallow removal of non-dynamic interfaces, or interfaces which are
261*bebae9c0SAndroid Build Coastguard Worker                 // currently being resumed (will not auto-cancel an asynchronous resume)
262*bebae9c0SAndroid Build Coastguard Worker                 result = SL_RESULT_PRECONDITIONS_VIOLATED;
263*bebae9c0SAndroid Build Coastguard Worker                 break;
264*bebae9c0SAndroid Build Coastguard Worker 
265*bebae9c0SAndroid Build Coastguard Worker             }
266*bebae9c0SAndroid Build Coastguard Worker 
267*bebae9c0SAndroid Build Coastguard Worker             object_unlock_exclusive(thisObject);
268*bebae9c0SAndroid Build Coastguard Worker         }
269*bebae9c0SAndroid Build Coastguard Worker     }
270*bebae9c0SAndroid Build Coastguard Worker #else
271*bebae9c0SAndroid Build Coastguard Worker     result = SL_RESULT_FEATURE_UNSUPPORTED;
272*bebae9c0SAndroid Build Coastguard Worker #endif
273*bebae9c0SAndroid Build Coastguard Worker 
274*bebae9c0SAndroid Build Coastguard Worker     SL_LEAVE_INTERFACE
275*bebae9c0SAndroid Build Coastguard Worker }
276*bebae9c0SAndroid Build Coastguard Worker 
277*bebae9c0SAndroid Build Coastguard Worker 
278*bebae9c0SAndroid Build Coastguard Worker // Called by a worker thread to handle an asynchronous ResumeInterface.
279*bebae9c0SAndroid Build Coastguard Worker // Parameter self is the DynamicInterface, and MPH specifies which interface to resume.
280*bebae9c0SAndroid Build Coastguard Worker 
HandleResume(void * self,void * ignored,int MPH)281*bebae9c0SAndroid Build Coastguard Worker static void HandleResume(void *self, void *ignored, int MPH)
282*bebae9c0SAndroid Build Coastguard Worker {
283*bebae9c0SAndroid Build Coastguard Worker 
284*bebae9c0SAndroid Build Coastguard Worker     // validate input parameters
285*bebae9c0SAndroid Build Coastguard Worker     IDynamicInterfaceManagement *thiz = (IDynamicInterfaceManagement *) self;
286*bebae9c0SAndroid Build Coastguard Worker     assert(NULL != thiz);
287*bebae9c0SAndroid Build Coastguard Worker     IObject *thisObject = InterfaceToIObject(thiz);
288*bebae9c0SAndroid Build Coastguard Worker     assert(NULL != thisObject);
289*bebae9c0SAndroid Build Coastguard Worker     assert(0 <= MPH && MPH < MPH_MAX);
290*bebae9c0SAndroid Build Coastguard Worker     const ClassTable *clazz = thisObject->mClass;
291*bebae9c0SAndroid Build Coastguard Worker     assert(NULL != clazz);
292*bebae9c0SAndroid Build Coastguard Worker     int index = clazz->mMPH_to_index[MPH];
293*bebae9c0SAndroid Build Coastguard Worker     assert(0 <= index && index < (int) clazz->mInterfaceCount);
294*bebae9c0SAndroid Build Coastguard Worker     SLuint8 *interfaceStateP = &thisObject->mInterfaceStates[index];
295*bebae9c0SAndroid Build Coastguard Worker     SLresult result;
296*bebae9c0SAndroid Build Coastguard Worker 
297*bebae9c0SAndroid Build Coastguard Worker     // check interface state
298*bebae9c0SAndroid Build Coastguard Worker     object_lock_exclusive(thisObject);
299*bebae9c0SAndroid Build Coastguard Worker     SLuint8 state = *interfaceStateP;
300*bebae9c0SAndroid Build Coastguard Worker     switch (state) {
301*bebae9c0SAndroid Build Coastguard Worker 
302*bebae9c0SAndroid Build Coastguard Worker     case INTERFACE_RESUMING_1:      // normal case
303*bebae9c0SAndroid Build Coastguard Worker         {
304*bebae9c0SAndroid Build Coastguard Worker         // change state to indicate we are now resuming the interface
305*bebae9c0SAndroid Build Coastguard Worker         *interfaceStateP = INTERFACE_RESUMING_2;
306*bebae9c0SAndroid Build Coastguard Worker         object_unlock_exclusive(thisObject);
307*bebae9c0SAndroid Build Coastguard Worker 
308*bebae9c0SAndroid Build Coastguard Worker         // this section runs with mutex unlocked
309*bebae9c0SAndroid Build Coastguard Worker         const struct iid_vtable *x = &clazz->mInterfaces[index];
310*bebae9c0SAndroid Build Coastguard Worker         size_t offset = x->mOffset;
311*bebae9c0SAndroid Build Coastguard Worker         void *thisItf = (char *) thisObject + offset;
312*bebae9c0SAndroid Build Coastguard Worker         VoidHook resume = MPH_init_table[MPH].mResume;
313*bebae9c0SAndroid Build Coastguard Worker         if (NULL != resume) {
314*bebae9c0SAndroid Build Coastguard Worker             (*resume)(thisItf);
315*bebae9c0SAndroid Build Coastguard Worker         }
316*bebae9c0SAndroid Build Coastguard Worker         result = SL_RESULT_SUCCESS;
317*bebae9c0SAndroid Build Coastguard Worker 
318*bebae9c0SAndroid Build Coastguard Worker         // re-lock mutex to update state
319*bebae9c0SAndroid Build Coastguard Worker         object_lock_exclusive(thisObject);
320*bebae9c0SAndroid Build Coastguard Worker         assert(INTERFACE_RESUMING_2 == *interfaceStateP);
321*bebae9c0SAndroid Build Coastguard Worker         state = INTERFACE_ADDED;
322*bebae9c0SAndroid Build Coastguard Worker         }
323*bebae9c0SAndroid Build Coastguard Worker         break;
324*bebae9c0SAndroid Build Coastguard Worker 
325*bebae9c0SAndroid Build Coastguard Worker     case INTERFACE_RESUMING_1A:     // operation was aborted while on work queue
326*bebae9c0SAndroid Build Coastguard Worker         result = SL_RESULT_OPERATION_ABORTED;
327*bebae9c0SAndroid Build Coastguard Worker         state = INTERFACE_SUSPENDED;
328*bebae9c0SAndroid Build Coastguard Worker         break;
329*bebae9c0SAndroid Build Coastguard Worker 
330*bebae9c0SAndroid Build Coastguard Worker     default:                        // impossible
331*bebae9c0SAndroid Build Coastguard Worker         assert(SL_BOOLEAN_FALSE);
332*bebae9c0SAndroid Build Coastguard Worker         result = SL_RESULT_INTERNAL_ERROR;
333*bebae9c0SAndroid Build Coastguard Worker         break;
334*bebae9c0SAndroid Build Coastguard Worker 
335*bebae9c0SAndroid Build Coastguard Worker     }
336*bebae9c0SAndroid Build Coastguard Worker 
337*bebae9c0SAndroid Build Coastguard Worker     // mutex is locked, update state
338*bebae9c0SAndroid Build Coastguard Worker     *interfaceStateP = state;
339*bebae9c0SAndroid Build Coastguard Worker 
340*bebae9c0SAndroid Build Coastguard Worker     // Make a copy of these, so we can call the callback with mutex unlocked
341*bebae9c0SAndroid Build Coastguard Worker     slDynamicInterfaceManagementCallback callback = thiz->mCallback;
342*bebae9c0SAndroid Build Coastguard Worker     void *context = thiz->mContext;
343*bebae9c0SAndroid Build Coastguard Worker     object_unlock_exclusive(thisObject);
344*bebae9c0SAndroid Build Coastguard Worker 
345*bebae9c0SAndroid Build Coastguard Worker     // Note that the mutex is unlocked during the callback
346*bebae9c0SAndroid Build Coastguard Worker     if (NULL != callback) {
347*bebae9c0SAndroid Build Coastguard Worker         const SLInterfaceID iid = &SL_IID_array[MPH]; // equal but not == to the original IID
348*bebae9c0SAndroid Build Coastguard Worker         (*callback)(&thiz->mItf, context, SL_DYNAMIC_ITF_EVENT_ASYNC_TERMINATION, result, iid);
349*bebae9c0SAndroid Build Coastguard Worker     }
350*bebae9c0SAndroid Build Coastguard Worker }
351*bebae9c0SAndroid Build Coastguard Worker 
352*bebae9c0SAndroid Build Coastguard Worker 
IDynamicInterfaceManagement_ResumeInterface(SLDynamicInterfaceManagementItf self,const SLInterfaceID iid,SLboolean async)353*bebae9c0SAndroid Build Coastguard Worker static SLresult IDynamicInterfaceManagement_ResumeInterface(SLDynamicInterfaceManagementItf self,
354*bebae9c0SAndroid Build Coastguard Worker     const SLInterfaceID iid, SLboolean async)
355*bebae9c0SAndroid Build Coastguard Worker {
356*bebae9c0SAndroid Build Coastguard Worker     SL_ENTER_INTERFACE
357*bebae9c0SAndroid Build Coastguard Worker 
358*bebae9c0SAndroid Build Coastguard Worker     // validate input parameters
359*bebae9c0SAndroid Build Coastguard Worker     if (NULL == iid) {
360*bebae9c0SAndroid Build Coastguard Worker         result = SL_RESULT_PARAMETER_INVALID;
361*bebae9c0SAndroid Build Coastguard Worker     } else {
362*bebae9c0SAndroid Build Coastguard Worker         IDynamicInterfaceManagement *thiz = (IDynamicInterfaceManagement *) self;
363*bebae9c0SAndroid Build Coastguard Worker         IObject *thisObject = InterfaceToIObject(thiz);
364*bebae9c0SAndroid Build Coastguard Worker         const ClassTable *clazz = thisObject->mClass;
365*bebae9c0SAndroid Build Coastguard Worker         int MPH, index;
366*bebae9c0SAndroid Build Coastguard Worker         if ((0 > (MPH = IID_to_MPH(iid))) ||
367*bebae9c0SAndroid Build Coastguard Worker                 // no need to check for an initialization hook
368*bebae9c0SAndroid Build Coastguard Worker                 // (NULL == MPH_init_table[MPH].mInit) ||
369*bebae9c0SAndroid Build Coastguard Worker                 (0 > (index = clazz->mMPH_to_index[MPH]))) {
370*bebae9c0SAndroid Build Coastguard Worker             result = SL_RESULT_PRECONDITIONS_VIOLATED;
371*bebae9c0SAndroid Build Coastguard Worker         } else {
372*bebae9c0SAndroid Build Coastguard Worker             assert(index < (int) clazz->mInterfaceCount);
373*bebae9c0SAndroid Build Coastguard Worker             SLuint8 *interfaceStateP = &thisObject->mInterfaceStates[index];
374*bebae9c0SAndroid Build Coastguard Worker 
375*bebae9c0SAndroid Build Coastguard Worker             // check interface state
376*bebae9c0SAndroid Build Coastguard Worker             object_lock_exclusive(thisObject);
377*bebae9c0SAndroid Build Coastguard Worker             switch (*interfaceStateP) {
378*bebae9c0SAndroid Build Coastguard Worker 
379*bebae9c0SAndroid Build Coastguard Worker             case INTERFACE_SUSPENDED:   // normal case
380*bebae9c0SAndroid Build Coastguard Worker                 if (async) {
381*bebae9c0SAndroid Build Coastguard Worker                     // Asynchronous: mark operation pending and cancellable
382*bebae9c0SAndroid Build Coastguard Worker                     *interfaceStateP = INTERFACE_RESUMING_1;
383*bebae9c0SAndroid Build Coastguard Worker                     object_unlock_exclusive(thisObject);
384*bebae9c0SAndroid Build Coastguard Worker 
385*bebae9c0SAndroid Build Coastguard Worker                     // this section runs with mutex unlocked
386*bebae9c0SAndroid Build Coastguard Worker                     result = ThreadPool_add_ppi(&thisObject->mEngine->mThreadPool, HandleResume,
387*bebae9c0SAndroid Build Coastguard Worker                         thiz, NULL, MPH);
388*bebae9c0SAndroid Build Coastguard Worker                     if (SL_RESULT_SUCCESS != result) {
389*bebae9c0SAndroid Build Coastguard Worker                         // Engine was destroyed during resume, or insufficient memory,
390*bebae9c0SAndroid Build Coastguard Worker                         // so restore mInterfaceStates state to prior value
391*bebae9c0SAndroid Build Coastguard Worker                         object_lock_exclusive(thisObject);
392*bebae9c0SAndroid Build Coastguard Worker                         switch (*interfaceStateP) {
393*bebae9c0SAndroid Build Coastguard Worker                         case INTERFACE_RESUMING_1:  // normal
394*bebae9c0SAndroid Build Coastguard Worker                         case INTERFACE_RESUMING_1A: // operation aborted while mutex unlocked
395*bebae9c0SAndroid Build Coastguard Worker                             *interfaceStateP = INTERFACE_SUSPENDED;
396*bebae9c0SAndroid Build Coastguard Worker                             break;
397*bebae9c0SAndroid Build Coastguard Worker                         default:                    // unexpected
398*bebae9c0SAndroid Build Coastguard Worker                             // leave state alone
399*bebae9c0SAndroid Build Coastguard Worker                             break;
400*bebae9c0SAndroid Build Coastguard Worker                         }
401*bebae9c0SAndroid Build Coastguard Worker                     }
402*bebae9c0SAndroid Build Coastguard Worker 
403*bebae9c0SAndroid Build Coastguard Worker                 } else {
404*bebae9c0SAndroid Build Coastguard Worker                     // Synchronous: mark operation pending to prevent duplication
405*bebae9c0SAndroid Build Coastguard Worker                     *interfaceStateP = INTERFACE_RESUMING_2;
406*bebae9c0SAndroid Build Coastguard Worker                     object_unlock_exclusive(thisObject);
407*bebae9c0SAndroid Build Coastguard Worker 
408*bebae9c0SAndroid Build Coastguard Worker                     // this section runs with mutex unlocked
409*bebae9c0SAndroid Build Coastguard Worker                     const struct iid_vtable *x = &clazz->mInterfaces[index];
410*bebae9c0SAndroid Build Coastguard Worker                     size_t offset = x->mOffset;
411*bebae9c0SAndroid Build Coastguard Worker                     void *thisItf = (char *) thiz + offset;
412*bebae9c0SAndroid Build Coastguard Worker                     VoidHook resume = MPH_init_table[MPH].mResume;
413*bebae9c0SAndroid Build Coastguard Worker                     if (NULL != resume) {
414*bebae9c0SAndroid Build Coastguard Worker                         (*resume)(thisItf);
415*bebae9c0SAndroid Build Coastguard Worker                     }
416*bebae9c0SAndroid Build Coastguard Worker                     result = SL_RESULT_SUCCESS;
417*bebae9c0SAndroid Build Coastguard Worker 
418*bebae9c0SAndroid Build Coastguard Worker                     // re-lock mutex to update state
419*bebae9c0SAndroid Build Coastguard Worker                     object_lock_exclusive(thisObject);
420*bebae9c0SAndroid Build Coastguard Worker                     assert(INTERFACE_RESUMING_2 == *interfaceStateP);
421*bebae9c0SAndroid Build Coastguard Worker                     *interfaceStateP = INTERFACE_ADDED;
422*bebae9c0SAndroid Build Coastguard Worker                 }
423*bebae9c0SAndroid Build Coastguard Worker 
424*bebae9c0SAndroid Build Coastguard Worker                 // mutex is now locked
425*bebae9c0SAndroid Build Coastguard Worker                 break;
426*bebae9c0SAndroid Build Coastguard Worker 
427*bebae9c0SAndroid Build Coastguard Worker             default:    // disallow resumption of non-suspended interfaces
428*bebae9c0SAndroid Build Coastguard Worker                 result = SL_RESULT_PRECONDITIONS_VIOLATED;
429*bebae9c0SAndroid Build Coastguard Worker                 break;
430*bebae9c0SAndroid Build Coastguard Worker             }
431*bebae9c0SAndroid Build Coastguard Worker 
432*bebae9c0SAndroid Build Coastguard Worker             object_unlock_exclusive(thisObject);
433*bebae9c0SAndroid Build Coastguard Worker         }
434*bebae9c0SAndroid Build Coastguard Worker     }
435*bebae9c0SAndroid Build Coastguard Worker 
436*bebae9c0SAndroid Build Coastguard Worker     SL_LEAVE_INTERFACE
437*bebae9c0SAndroid Build Coastguard Worker }
438*bebae9c0SAndroid Build Coastguard Worker 
439*bebae9c0SAndroid Build Coastguard Worker 
IDynamicInterfaceManagement_RegisterCallback(SLDynamicInterfaceManagementItf self,slDynamicInterfaceManagementCallback callback,void * pContext)440*bebae9c0SAndroid Build Coastguard Worker static SLresult IDynamicInterfaceManagement_RegisterCallback(SLDynamicInterfaceManagementItf self,
441*bebae9c0SAndroid Build Coastguard Worker     slDynamicInterfaceManagementCallback callback, void *pContext)
442*bebae9c0SAndroid Build Coastguard Worker {
443*bebae9c0SAndroid Build Coastguard Worker     SL_ENTER_INTERFACE
444*bebae9c0SAndroid Build Coastguard Worker 
445*bebae9c0SAndroid Build Coastguard Worker     IDynamicInterfaceManagement *thiz = (IDynamicInterfaceManagement *) self;
446*bebae9c0SAndroid Build Coastguard Worker     IObject *thisObject = InterfaceToIObject(thiz);
447*bebae9c0SAndroid Build Coastguard Worker     object_lock_exclusive(thisObject);
448*bebae9c0SAndroid Build Coastguard Worker     thiz->mCallback = callback;
449*bebae9c0SAndroid Build Coastguard Worker     thiz->mContext = pContext;
450*bebae9c0SAndroid Build Coastguard Worker     object_unlock_exclusive(thisObject);
451*bebae9c0SAndroid Build Coastguard Worker     result = SL_RESULT_SUCCESS;
452*bebae9c0SAndroid Build Coastguard Worker 
453*bebae9c0SAndroid Build Coastguard Worker     SL_LEAVE_INTERFACE
454*bebae9c0SAndroid Build Coastguard Worker }
455*bebae9c0SAndroid Build Coastguard Worker 
456*bebae9c0SAndroid Build Coastguard Worker 
457*bebae9c0SAndroid Build Coastguard Worker static const struct SLDynamicInterfaceManagementItf_ IDynamicInterfaceManagement_Itf = {
458*bebae9c0SAndroid Build Coastguard Worker     IDynamicInterfaceManagement_AddInterface,
459*bebae9c0SAndroid Build Coastguard Worker     IDynamicInterfaceManagement_RemoveInterface,
460*bebae9c0SAndroid Build Coastguard Worker     IDynamicInterfaceManagement_ResumeInterface,
461*bebae9c0SAndroid Build Coastguard Worker     IDynamicInterfaceManagement_RegisterCallback
462*bebae9c0SAndroid Build Coastguard Worker };
463*bebae9c0SAndroid Build Coastguard Worker 
IDynamicInterfaceManagement_init(void * self)464*bebae9c0SAndroid Build Coastguard Worker void IDynamicInterfaceManagement_init(void *self)
465*bebae9c0SAndroid Build Coastguard Worker {
466*bebae9c0SAndroid Build Coastguard Worker     IDynamicInterfaceManagement *thiz = (IDynamicInterfaceManagement *) self;
467*bebae9c0SAndroid Build Coastguard Worker     thiz->mItf = &IDynamicInterfaceManagement_Itf;
468*bebae9c0SAndroid Build Coastguard Worker     thiz->mCallback = NULL;
469*bebae9c0SAndroid Build Coastguard Worker     thiz->mContext = NULL;
470*bebae9c0SAndroid Build Coastguard Worker }
471