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