CFPlugIn.c
1 /* CFPlugIn.c 2 Copyright (c) 1999-2019, Apple Inc. and the Swift project authors 3 4 Portions Copyright (c) 2014-2019, Apple Inc. and the Swift project authors 5 Licensed under Apache License v2.0 with Runtime Library Exception 6 See http://swift.org/LICENSE.txt for license information 7 See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors 8 Responsibility: Tony Parker 9 */ 10 11 #include "CFBundle_Internal.h" 12 #include "CFInternal.h" 13 #include "CFRuntime_Internal.h" 14 15 16 // MARK: - Declarations 17 18 static os_log_t _CFBundlePluginLogger(void); 19 20 static _CFPFactoryRef _CFPFactoryCommonCreateLocked(CFAllocatorRef allocator, CFUUIDRef factoryID); 21 22 static _CFPFactoryRef _CFPFactoryFindLocked(CFUUIDRef factoryID, Boolean enabled); 23 24 static CFUUIDRef _CFPFactoryCopyFactoryIDLocked(_CFPFactoryRef factory); 25 static CFPlugInRef _CFPFactoryCopyPlugInLocked(_CFPFactoryRef factory); 26 27 static void _CFPlugInRegisterFactoryFunctionByNameLocked(CFUUIDRef factoryID, CFPlugInRef plugIn, CFStringRef functionName); 28 static void _CFPlugInRegisterPlugInTypeLocked(CFUUIDRef factoryID, CFUUIDRef typeID); 29 30 static void _CFPFactoryDisableLocked(_CFPFactoryRef factory); 31 static void *__CFPLUGIN_IS_CALLING_OUT_TO_A_FACTORY_FUNCTION__(CFPlugInFactoryFunction, CFAllocatorRef, CFUUIDRef) __attribute__((noinline)); 32 33 34 static void _CFPFactoryAddTypeLocked(_CFPFactoryRef factory, CFUUIDRef typeID); 35 static void _CFPFactoryRemoveTypeLocked(_CFPFactoryRef factory, CFUUIDRef typeID); 36 static Boolean _CFPFactorySupportsTypeLocked(_CFPFactoryRef factory, CFUUIDRef typeID); 37 38 /* These methods are called by CFPlugInInstance when an instance is created or destroyed. If a factory's instance count goes to 0 and the factory has been disabled, the factory is destroyed. */ 39 static void _CFPFactoryAddInstanceLocked(_CFPFactoryRef factory); 40 static void _CFPFactoryRemoveInstanceLocked(_CFPFactoryRef factory); 41 42 static void _CFPlugInAddPlugInInstanceLocked(CFPlugInRef plugIn); 43 static void _CFPlugInRemovePlugInInstanceLocked(CFPlugInRef plugIn); 44 static void _CFPlugInIncrementUnloadPreventionLocked(CFPlugInRef plugIn); 45 static void _CFPlugInDecrementUnloadPreventionLocked(CFPlugInRef plugIn); 46 47 static void _CFPlugInAddFactoryLocked(CFPlugInRef plugIn, _CFPFactoryRef factory); 48 static void _CFPlugInRemoveFactoryLocked(CFPlugInRef plugIn, _CFPFactoryRef factory); 49 50 CONST_STRING_DECL(kCFPlugInDynamicRegistrationKey, "CFPlugInDynamicRegistration") 51 CONST_STRING_DECL(kCFPlugInDynamicRegisterFunctionKey, "CFPlugInDynamicRegisterFunction") 52 CONST_STRING_DECL(kCFPlugInUnloadFunctionKey, "CFPlugInUnloadFunction") 53 CONST_STRING_DECL(kCFPlugInFactoriesKey, "CFPlugInFactories") 54 CONST_STRING_DECL(kCFPlugInTypesKey, "CFPlugInTypes") 55 56 struct __CFPlugInInstance { 57 CFRuntimeBase _base; 58 59 _CFPFactoryRef factory; 60 61 CFPlugInInstanceGetInterfaceFunction getInterfaceFunction; 62 CFPlugInInstanceDeallocateInstanceDataFunction deallocateInstanceDataFunction; 63 64 #ifdef _MSC_VER 65 #pragma warning(push) 66 #pragma warning(disable : 4200) 67 #endif //_MSC_VER 68 uint8_t _instanceData[0]; 69 #ifdef _MSC_VER 70 #pragma warning(pop) 71 #endif //_MSC_VER 72 }; 73 74 75 struct __CFPFactory { 76 CFRuntimeBase _base; 77 78 // All protected by CFPlugInGlobalDataLock 79 CFUUIDRef _uuid; 80 Boolean _enabled; 81 char _padding[3]; 82 83 CFPlugInFactoryFunction _func; 84 85 CFPlugInRef _plugIn; 86 CFStringRef _funcName; 87 88 CFMutableArrayRef _types; 89 }; 90 91 // Plugin state is stored in several places: 92 // 1. The following factories by factory/typeID tables 93 // 2. The list of supported types in each factory instance 94 // 3. The enabled flag in each factory instance 95 // 4. The plugInData inside each bundle instance (except isPlugIn, which is constant after init) 96 // In order to synchronize all of this, there is one global lock for all of it. 97 os_unfair_recursive_lock CFPlugInGlobalDataLock = OS_UNFAIR_RECURSIVE_LOCK_INIT; 98 static CFMutableDictionaryRef _factoriesByFactoryID = NULL; /* Value is _CFPFactoryRef */ 99 static CFMutableDictionaryRef _factoriesByTypeID = NULL; /* Value is array of _CFPFactoryRef */ 100 static CFMutableSetRef _plugInsToUnload = NULL; 101 102 // MARK: - Plugin 103 104 static os_log_t _CFBundlePluginLogger(void) { 105 static os_log_t _log; 106 static dispatch_once_t onceToken; 107 dispatch_once(&onceToken, ^{ 108 _log = os_log_create("com.apple.CFBundle", "plugin"); 109 }); 110 return _log; 111 } 112 113 CF_EXPORT void *CFPlugInInstanceCreate(CFAllocatorRef allocator, CFUUIDRef factoryID, CFUUIDRef typeID) { 114 void *result = NULL; 115 CFPlugInFactoryFunction f = NULL; 116 117 os_unfair_recursive_lock_lock_with_options(&CFPlugInGlobalDataLock, OS_UNFAIR_LOCK_DATA_SYNCHRONIZATION); 118 _CFPFactoryRef factory = _CFPFactoryFindLocked(factoryID, true); 119 if (!factory) { 120 os_log_error(_CFBundlePluginLogger(), "Cannot find factory %{public}@", factoryID); 121 } else { 122 if (!_CFPFactorySupportsTypeLocked(factory, typeID)) { 123 os_log_error(_CFBundlePluginLogger(), "Factory %{public}@ does not support type %{public}@", factoryID, typeID); 124 } else if (factory->_enabled) { 125 if (!factory->_func) { 126 factory->_func = (CFPlugInFactoryFunction)CFBundleGetFunctionPointerForName(factory->_plugIn, factory->_funcName); 127 128 if (!factory->_func) { 129 os_log_error(_CFBundlePluginLogger(), "Cannot find function pointer %{public}@ for factory %{public}@ in %{public}@", factory->_funcName, factory->_uuid, factory->_plugIn); 130 } 131 } 132 if (factory->_func) { 133 f = factory->_func; 134 135 // Not every factory comes from a plugin, but if it does, we must prevent unload of the plugin so that the function pointer 'f' remains valid, even if factory->_func is cleared. 136 if (factory->_plugIn) { 137 _CFPlugInIncrementUnloadPreventionLocked(factory->_plugIn); 138 } 139 } 140 } else { 141 os_log_debug(_CFBundlePluginLogger(), "Attempted to create instance, but factory %{public}@ is disabled", factory->_uuid); 142 } 143 } 144 os_unfair_recursive_lock_unlock(&CFPlugInGlobalDataLock); 145 146 // Call out to the factory function outside of the lock 147 if (f) { 148 result = __CFPLUGIN_IS_CALLING_OUT_TO_A_FACTORY_FUNCTION__(f, allocator, typeID); 149 os_log_debug(_CFBundlePluginLogger(), "Created instance of plugin for factory %{public}@ type %{public}@", factoryID, typeID); 150 151 os_unfair_recursive_lock_lock(&CFPlugInGlobalDataLock); 152 if (factory->_plugIn) { 153 _CFPlugInDecrementUnloadPreventionLocked(factory->_plugIn); 154 } 155 os_unfair_recursive_lock_unlock(&CFPlugInGlobalDataLock); 156 } 157 158 return result; 159 } 160 161 /* ===================== Registering factories and types ===================== */ 162 /* For plugIn writers who must dynamically register things. */ 163 /* Functions to register factory functions and to associate factories with types. */ 164 165 CF_EXPORT Boolean CFPlugInRegisterFactoryFunction(CFUUIDRef factoryID, CFPlugInFactoryFunction func) { 166 // Create factories without plugIns from default allocator 167 // MF:!!! Should probably check that this worked, and maybe do some pre-checking to see if it already exists 168 169 os_unfair_recursive_lock_lock_with_options(&CFPlugInGlobalDataLock, OS_UNFAIR_LOCK_DATA_SYNCHRONIZATION); 170 171 _CFPFactoryRef factory = _CFPFactoryCommonCreateLocked(kCFAllocatorSystemDefault, factoryID); 172 factory->_func = func; 173 factory->_plugIn = NULL; 174 factory->_funcName = NULL; 175 176 os_unfair_recursive_lock_unlock(&CFPlugInGlobalDataLock); 177 178 return true; 179 } 180 181 CF_EXPORT Boolean CFPlugInRegisterFactoryFunctionByName(CFUUIDRef factoryID, CFPlugInRef plugIn, CFStringRef functionName) { 182 // Create factories with plugIns from plugIn's allocator 183 // MF:!!! Should probably check that this worked, and maybe do some pre-checking to see if it already exists 184 os_unfair_recursive_lock_lock_with_options(&CFPlugInGlobalDataLock, OS_UNFAIR_LOCK_DATA_SYNCHRONIZATION); 185 _CFPlugInRegisterFactoryFunctionByNameLocked(factoryID, plugIn, functionName); 186 os_unfair_recursive_lock_unlock(&CFPlugInGlobalDataLock); 187 188 return true; 189 } 190 191 static void _CFPlugInRegisterFactoryFunctionByNameLocked(CFUUIDRef factoryID, CFPlugInRef plugIn, CFStringRef functionName) { 192 _CFPFactoryRef factory = _CFPFactoryCommonCreateLocked(kCFAllocatorSystemDefault, factoryID); 193 factory->_func = NULL; 194 factory->_plugIn = (CFPlugInRef)CFRetain(plugIn); 195 if (plugIn) _CFPlugInAddFactoryLocked(plugIn, factory); 196 factory->_funcName = (functionName ? (CFStringRef)CFStringCreateCopy(kCFAllocatorSystemDefault, functionName) : NULL); 197 } 198 199 200 CF_EXPORT Boolean CFPlugInUnregisterFactory(CFUUIDRef factoryID) { 201 os_unfair_recursive_lock_lock_with_options(&CFPlugInGlobalDataLock, OS_UNFAIR_LOCK_DATA_SYNCHRONIZATION); 202 203 _CFPFactoryRef factory = _CFPFactoryFindLocked(factoryID, true); 204 205 if (!factory) { 206 /* MF:!!! Error. No factory registered for this ID. */ 207 os_log_error(_CFBundlePluginLogger(), "UnregisterFactory: No factory registered for id %{public}@", factoryID); 208 } else { 209 _CFPFactoryDisableLocked(factory); 210 } 211 os_unfair_recursive_lock_unlock(&CFPlugInGlobalDataLock); 212 213 return true; 214 } 215 216 CF_EXPORT Boolean CFPlugInRegisterPlugInType(CFUUIDRef factoryID, CFUUIDRef typeID) { 217 os_unfair_recursive_lock_lock_with_options(&CFPlugInGlobalDataLock, OS_UNFAIR_LOCK_DATA_SYNCHRONIZATION); 218 _CFPlugInRegisterPlugInTypeLocked(factoryID, typeID); 219 os_unfair_recursive_lock_unlock(&CFPlugInGlobalDataLock); 220 221 return true; 222 } 223 224 static void _CFPlugInRegisterPlugInTypeLocked(CFUUIDRef factoryID, CFUUIDRef typeID) { 225 _CFPFactoryRef factory = _CFPFactoryFindLocked(factoryID, true); 226 227 if (!factory) { 228 /* MF:!!! Error. Factory must be registered (and not disabled) before types can be associated with it. */ 229 os_log_error(_CFBundlePluginLogger(), "RegisterPlugInType: No factory registered for id %{public}@", factoryID); 230 } else { 231 _CFPFactoryAddTypeLocked(factory, typeID); 232 } 233 } 234 235 236 CF_EXPORT Boolean CFPlugInUnregisterPlugInType(CFUUIDRef factoryID, CFUUIDRef typeID) { 237 os_unfair_recursive_lock_lock_with_options(&CFPlugInGlobalDataLock, OS_UNFAIR_LOCK_DATA_SYNCHRONIZATION); 238 239 _CFPFactoryRef factory = _CFPFactoryFindLocked(factoryID, true); 240 241 if (!factory) { 242 /* MF:!!! Error. Could not find factory. */ 243 os_log_error(_CFBundlePluginLogger(), "UnregisterPlugInType: No factory registered for id %{public}@ type %{public}@", factoryID, typeID); 244 } else { 245 _CFPFactoryRemoveTypeLocked(factory, typeID); 246 } 247 248 os_unfair_recursive_lock_unlock(&CFPlugInGlobalDataLock); 249 250 return true; 251 } 252 253 254 /* ================= Registering instances ================= */ 255 /* When a new instance of a type is created, the instance is responsible for registering itself with the factory that created it and unregistering when it deallocates. */ 256 /* This means that an instance must keep track of the CFUUIDRef of the factory that created it so it can unregister when it goes away. */ 257 258 CF_EXPORT void CFPlugInAddInstanceForFactory(CFUUIDRef factoryID) { 259 os_unfair_recursive_lock_lock_with_options(&CFPlugInGlobalDataLock, OS_UNFAIR_LOCK_DATA_SYNCHRONIZATION); 260 261 _CFPFactoryRef factory = _CFPFactoryFindLocked(factoryID, true); 262 263 if (!factory) { 264 /* MF:!!! Error. Could not find factory. */ 265 os_log_error(_CFBundlePluginLogger(), "AddInstanceForFactory: No factory registered for id %{public}@", factoryID); 266 } else { 267 _CFPFactoryAddInstanceLocked(factory); 268 os_log_debug(_CFBundlePluginLogger(), "AddInstanceForFactory: Added instance on %p for %{public}@", factory, factoryID); 269 } 270 271 os_unfair_recursive_lock_unlock(&CFPlugInGlobalDataLock); 272 } 273 274 CF_EXPORT void CFPlugInRemoveInstanceForFactory(CFUUIDRef factoryID) { 275 os_unfair_recursive_lock_lock_with_options(&CFPlugInGlobalDataLock, OS_UNFAIR_LOCK_DATA_SYNCHRONIZATION); 276 277 _CFPFactoryRef factory = _CFPFactoryFindLocked(factoryID, true); 278 279 if (!factory) { 280 /* MF:!!! Error. Could not find factory. */ 281 os_log_error(_CFBundlePluginLogger(), "RemoveInstanceForFactory: No factory registered for id %{public}@", factoryID); 282 } else { 283 _CFPFactoryRemoveInstanceLocked(factory); 284 os_log_debug(_CFBundlePluginLogger(), "RemoveInstanceForFactory: Removed instance on %p for %{public}@", factory, factoryID); 285 } 286 287 os_unfair_recursive_lock_unlock(&CFPlugInGlobalDataLock); 288 } 289 290 // MARK: Plugin - Unloading 291 292 static void _CFPlugInScheduleForUnloading(CFBundleRef bundle) { 293 os_unfair_recursive_lock_lock_with_options(&CFPlugInGlobalDataLock, OS_UNFAIR_LOCK_DATA_SYNCHRONIZATION); 294 if (!_plugInsToUnload) { 295 CFSetCallBacks nonRetainingCallbacks = kCFTypeSetCallBacks; 296 nonRetainingCallbacks.retain = NULL; 297 nonRetainingCallbacks.release = NULL; 298 _plugInsToUnload = CFSetCreateMutable(kCFAllocatorSystemDefault, 0, &nonRetainingCallbacks); 299 } 300 CFSetAddValue(_plugInsToUnload, bundle); 301 os_log_debug(_CFBundlePluginLogger(), "PlugIn %{public}@ is now scheduled for unloading", bundle); 302 os_unfair_recursive_lock_unlock(&CFPlugInGlobalDataLock); 303 } 304 305 CF_PRIVATE void _CFPlugInUnscheduleForUnloading(CFBundleRef bundle) { 306 os_unfair_recursive_lock_lock_with_options(&CFPlugInGlobalDataLock, OS_UNFAIR_LOCK_DATA_SYNCHRONIZATION); 307 if (_plugInsToUnload) CFSetRemoveValue(_plugInsToUnload, bundle); 308 os_log_debug(_CFBundlePluginLogger(), "PlugIn %{public}@ is now unscheduled for unloading", bundle); 309 os_unfair_recursive_lock_unlock(&CFPlugInGlobalDataLock); 310 } 311 312 CF_PRIVATE void _CFPlugInUnloadScheduledPlugIns(void) { 313 os_unfair_recursive_lock_lock_with_options(&CFPlugInGlobalDataLock, OS_UNFAIR_LOCK_DATA_SYNCHRONIZATION); 314 if (_plugInsToUnload) { 315 CFIndex i, c = CFSetGetCount(_plugInsToUnload); 316 if (c > 0) { 317 CFBundleRef *unloadThese = (CFBundleRef *)CFAllocatorAllocate(kCFAllocatorSystemDefault, sizeof(CFBundleRef) * c, 0); 318 CFSetGetValues(_plugInsToUnload, (const void **)unloadThese); 319 for (i = 0; i < c; i++) { 320 // This will cause them to be removed from the set. (Which is why we copied all the values out of the set up front.) 321 CFBundleRef unloadMe = unloadThese[i]; 322 323 // If its unloadPreventionCount is > 0 then leave it in the set and unload it the next time someone asks 324 if (__CFBundleGetPlugInData(unloadMe)->_unloadPreventionCount == 0) { 325 os_log_debug(_CFBundlePluginLogger(), "PlugIn %{public}@ is about to be unloaded", unloadMe); 326 _CFBundleUnloadExecutable(unloadMe, true); 327 } 328 } 329 CFAllocatorDeallocate(kCFAllocatorSystemDefault, unloadThese); 330 } 331 } 332 os_unfair_recursive_lock_unlock(&CFPlugInGlobalDataLock); 333 } 334 335 // MARK: Plugin - Internals 336 337 static void _searchForDummyUUID(const void *key, const void *val, void *context) { 338 Boolean *found = (Boolean *)context; 339 if (*found) { 340 // No need to continue searching here 341 return; 342 } 343 344 CFStringRef factoryIDStr = (CFStringRef)key; 345 if (CFGetTypeID(factoryIDStr) != CFStringGetTypeID()) { 346 // Factory ID is not a string, skip this entry 347 return; 348 } 349 350 if (CFStringCompare(factoryIDStr, CFSTR("00000000-0000-0000-0000-000000000000"), 0) == kCFCompareEqualTo) { 351 // This is a dummy UUID. Don't count this as a plugin if it uses the dummy function name too. 352 CFStringRef factoryFunctionStr = (CFStringRef)val; 353 if (factoryFunctionStr && CFGetTypeID(factoryFunctionStr) == CFStringGetTypeID()) { 354 if (CFStringCompare(factoryFunctionStr, CFSTR("MyFactoryFunction"), 0) == kCFCompareEqualTo) { 355 *found = true; 356 } 357 } 358 } 359 } 360 361 static void _searchForExistingFactoryLocked(const void *key, const void *val, void *context) { 362 CFBundleRef *found = (CFBundleRef *)context; 363 if (*found) { 364 // No need to continue searching here 365 return; 366 } 367 368 CFStringRef factoryIDStr = (CFStringRef)key; 369 CFUUIDRef factoryID = (CFGetTypeID(factoryIDStr) == CFStringGetTypeID()) ? CFUUIDCreateFromString(kCFAllocatorSystemDefault, factoryIDStr) : NULL; 370 if (!factoryID) factoryID = (CFUUIDRef)CFRetain(factoryIDStr); 371 372 // Match any factory, not just enabled ones 373 _CFPFactoryRef existing = _CFPFactoryFindLocked(factoryID, false); 374 if (existing) { 375 *found = (CFBundleRef)CFRetain(existing->_plugIn); 376 } 377 378 if (factoryID) CFRelease(factoryID); 379 } 380 381 static void _registerFactoryLocked(const void *key, const void *val, void *context) { 382 CFStringRef factoryIDStr = (CFStringRef)key; 383 CFStringRef factoryFuncStr = (CFStringRef)val; 384 CFBundleRef bundle = (CFBundleRef)context; 385 CFUUIDRef factoryID = (CFGetTypeID(factoryIDStr) == CFStringGetTypeID()) ? CFUUIDCreateFromString(kCFAllocatorSystemDefault, factoryIDStr) : NULL; 386 if (!factoryID) factoryID = (CFUUIDRef)CFRetain(factoryIDStr); 387 if (CFGetTypeID(factoryFuncStr) != CFStringGetTypeID() || CFStringGetLength(factoryFuncStr) <= 0) factoryFuncStr = NULL; 388 389 os_log_debug(_CFBundlePluginLogger(), "Registering static factory %{public}@ %{public}@ bundle %{public}p", factoryID, factoryFuncStr ?: CFSTR("<no func>"), bundle); 390 391 _CFPlugInRegisterFactoryFunctionByNameLocked(factoryID, bundle, factoryFuncStr); 392 if (factoryID) CFRelease(factoryID); 393 } 394 395 static void _registerTypeLocked(const void *key, const void *val, void *context) { 396 CFStringRef typeIDStr = (CFStringRef)key; 397 CFArrayRef factoryIDStrArray = (CFArrayRef)val; 398 CFBundleRef bundle = (CFBundleRef)context; 399 SInt32 i, c = (CFGetTypeID(factoryIDStrArray) == CFArrayGetTypeID()) ? CFArrayGetCount(factoryIDStrArray) : 0; 400 CFStringRef curFactoryIDStr; 401 CFUUIDRef typeID = (CFGetTypeID(typeIDStr) == CFStringGetTypeID()) ? CFUUIDCreateFromString(kCFAllocatorSystemDefault, typeIDStr) : NULL; 402 CFUUIDRef curFactoryID; 403 if (!typeID) typeID = (CFUUIDRef)CFRetain(typeIDStr); 404 if (0 == c && CFGetTypeID(factoryIDStrArray) != CFArrayGetTypeID()) { 405 curFactoryIDStr = (CFStringRef)val; 406 curFactoryID = (CFGetTypeID(curFactoryIDStr) == CFStringGetTypeID()) ? CFUUIDCreateFromString(CFGetAllocator(bundle), curFactoryIDStr) : NULL; 407 if (!curFactoryID) curFactoryID = (CFUUIDRef)CFRetain(curFactoryIDStr); 408 os_log_debug(_CFBundlePluginLogger(), "Registering factory %{public}@ type %{public}@", curFactoryID, typeID); 409 _CFPlugInRegisterPlugInTypeLocked(curFactoryID, typeID); 410 if (curFactoryID) CFRelease(curFactoryID); 411 } else for (i = 0; i < c; i++) { 412 curFactoryIDStr = (CFStringRef)CFArrayGetValueAtIndex(factoryIDStrArray, i); 413 curFactoryID = (CFGetTypeID(curFactoryIDStr) == CFStringGetTypeID()) ? CFUUIDCreateFromString(CFGetAllocator(bundle), curFactoryIDStr) : NULL; 414 if (!curFactoryID) curFactoryID = (CFUUIDRef)CFRetain(curFactoryIDStr); 415 os_log_debug(_CFBundlePluginLogger(), "Registering factory %{public}@ type %{public}@", curFactoryID, typeID); 416 _CFPlugInRegisterPlugInTypeLocked(curFactoryID, typeID); 417 if (curFactoryID) CFRelease(curFactoryID); 418 } 419 if (typeID) CFRelease(typeID); 420 } 421 422 // Returns false if we found another plugin with the same factory ID. 423 // Important: Do not call out to user code from here, as it is called with the global bundle lock taken. The lock ordering must be: 424 // CFBundleGlobalDataLock -> CFPlugInGlobalDataLock 425 // PlugIn lock is recursive but the bundle lock is not 426 CF_PRIVATE Boolean _CFBundleInitPlugIn(CFBundleRef bundle, CFDictionaryRef infoDict, CFBundleRef *existingPlugIn) { 427 CFArrayCallBacks _pluginFactoryArrayCallbacks = {0, NULL, NULL, NULL, NULL}; 428 Boolean doDynamicReg = false; 429 CFDictionaryRef factoryDict; 430 CFDictionaryRef typeDict; 431 CFStringRef tempStr; 432 433 if (!infoDict) return true; 434 435 factoryDict = (CFDictionaryRef)CFDictionaryGetValue(infoDict, kCFPlugInFactoriesKey); 436 if (factoryDict && CFGetTypeID(factoryDict) != CFDictionaryGetTypeID()) factoryDict = NULL; 437 tempStr = (CFStringRef)CFDictionaryGetValue(infoDict, kCFPlugInDynamicRegistrationKey); 438 if (tempStr && CFGetTypeID(tempStr) == CFStringGetTypeID() && CFStringCompare(tempStr, CFSTR("YES"), kCFCompareCaseInsensitive) == kCFCompareEqualTo) doDynamicReg = true; 439 if (!factoryDict && !doDynamicReg) return true; // This is not a plug-in. 440 441 // Search for placeholder UUIDs (all zero) 442 Boolean foundDummy = false; 443 if (factoryDict) CFDictionaryApplyFunction(factoryDict, _searchForDummyUUID, &foundDummy); 444 if (foundDummy) { 445 // Not a plugin. This combination seems to be part of a template, and is often left in Info.plists without much consideration. 446 os_log_debug(_CFBundlePluginLogger(), "Bundle %{public}@ contains a factory UUID of 00000000-0000-0000-0000-000000000000 with function 'MyFactoryFunction'. This bundle is not a valid plugin.", bundle); 447 return true; 448 } 449 450 os_unfair_recursive_lock_lock_with_options(&CFPlugInGlobalDataLock, OS_UNFAIR_LOCK_DATA_SYNCHRONIZATION); 451 452 if (__CFBundleGetPlugInData(bundle)->_registeredFactory) { 453 // We already registered - don't do it again 454 os_unfair_recursive_lock_unlock(&CFPlugInGlobalDataLock); 455 return true; 456 } 457 458 // Look for existing plugins with this factory ID 459 CFBundleRef found = NULL; 460 if (factoryDict) CFDictionaryApplyFunction(factoryDict, _searchForExistingFactoryLocked, &found); 461 if (found) { 462 if (existingPlugIn) { 463 *existingPlugIn = found; 464 } 465 os_unfair_recursive_lock_unlock(&CFPlugInGlobalDataLock); 466 return false; 467 } 468 469 /* loadOnDemand is true by default if the plugIn does not do dynamic registration. It is false, by default if it does do dynamic registration. The dynamic register function can set this. */ 470 __CFBundleGetPlugInData(bundle)->_isPlugIn = true; 471 __CFBundleGetPlugInData(bundle)->_loadOnDemand = true; 472 __CFBundleGetPlugInData(bundle)->_isDoingDynamicRegistration = false; 473 // It is the responsibility of the caller of this function to call _CFPlugInHandleDynamicRegistration once we are out of critical sections 474 __CFBundleGetPlugInData(bundle)->_needsDynamicRegistration = doDynamicReg; 475 __CFBundleGetPlugInData(bundle)->_instanceCount = 0; 476 __CFBundleGetPlugInData(bundle)->_unloadPreventionCount = 0; 477 __CFBundleGetPlugInData(bundle)->_registeredFactory = true; 478 479 __CFBundleGetPlugInData(bundle)->_factories = CFArrayCreateMutable(CFGetAllocator(bundle), 0, &_pluginFactoryArrayCallbacks); 480 481 /* Now do the registration */ 482 483 /* First do static registrations, if any. */ 484 if (factoryDict) CFDictionaryApplyFunction(factoryDict, _registerFactoryLocked, bundle); 485 typeDict = (CFDictionaryRef)CFDictionaryGetValue(infoDict, kCFPlugInTypesKey); 486 if (typeDict && CFGetTypeID(typeDict) != CFDictionaryGetTypeID()) typeDict = NULL; 487 if (typeDict) CFDictionaryApplyFunction(typeDict, _registerTypeLocked, bundle); 488 489 os_unfair_recursive_lock_unlock(&CFPlugInGlobalDataLock); 490 491 return true; 492 } 493 494 static void __CFPLUGIN_IS_CALLING_OUT_TO_A_DYNAMIC_REGISTRATION_FUNCTION__(CFPlugInDynamicRegisterFunction f, CFBundleRef bundle) __attribute__((noinline)); 495 496 static void __CFPLUGIN_IS_CALLING_OUT_TO_A_DYNAMIC_REGISTRATION_FUNCTION__(CFPlugInDynamicRegisterFunction f, CFBundleRef bundle) { 497 f(bundle); 498 __asm __volatile__(""); // thwart tail-call optimization 499 } 500 501 CF_PRIVATE void _CFPlugInHandleDynamicRegistration(CFBundleRef bundle) { 502 _CFPlugInData *plugIn = __CFBundleGetPlugInData(bundle); 503 504 // In order to proceed, it must be a plugin, loaded, and need dynamic registration 505 if (!(plugIn->_isPlugIn && CFBundleIsExecutableLoaded(bundle) && plugIn->_needsDynamicRegistration)) { 506 return; 507 } 508 509 os_unfair_recursive_lock_lock_with_options(&CFPlugInGlobalDataLock, OS_UNFAIR_LOCK_DATA_SYNCHRONIZATION); 510 511 if (plugIn->_isDoingDynamicRegistration) { 512 os_unfair_recursive_lock_unlock(&CFPlugInGlobalDataLock); 513 return; 514 } 515 516 plugIn->_needsDynamicRegistration = false; 517 CFDictionaryRef infoDict = CFBundleGetInfoDictionary(bundle); 518 CFStringRef tempStr = (CFStringRef)CFDictionaryGetValue(infoDict, kCFPlugInDynamicRegisterFunctionKey); 519 if (!tempStr || CFGetTypeID(tempStr) != CFStringGetTypeID() || CFStringGetLength(tempStr) <= 0) tempStr = CFSTR("CFPlugInDynamicRegister"); 520 plugIn->_loadOnDemand = false; 521 522 plugIn->_isDoingDynamicRegistration = true; 523 524 CFPlugInDynamicRegisterFunction func = (CFPlugInDynamicRegisterFunction)CFBundleGetFunctionPointerForName(bundle, tempStr); 525 if (func) { 526 __CFPLUGIN_IS_CALLING_OUT_TO_A_DYNAMIC_REGISTRATION_FUNCTION__(func, bundle); 527 } 528 529 plugIn->_isDoingDynamicRegistration = false; 530 531 if (plugIn->_loadOnDemand && plugIn->_instanceCount == 0) CFBundleUnloadExecutable(bundle); // Unload now if we can/should. 532 533 os_unfair_recursive_lock_unlock(&CFPlugInGlobalDataLock); 534 } 535 536 CF_PRIVATE void _CFBundleDeallocatePlugIn(CFBundleRef bundle) { 537 _CFPlugInData *plugIn = __CFBundleGetPlugInData(bundle); 538 os_unfair_recursive_lock_lock_with_options(&CFPlugInGlobalDataLock, OS_UNFAIR_LOCK_DATA_SYNCHRONIZATION); 539 if (plugIn->_isPlugIn) { 540 /* Go through factories disabling them. Disabling these factories should cause them to dealloc since we wouldn't be deallocating if any of the factories had outstanding instances. So go backwards. */ 541 os_log_debug(_CFBundlePluginLogger(), "Disabling factories in array %{public}p for bundle %{public}p", __CFBundleGetPlugInData(bundle)->_factories, bundle); 542 SInt32 c = CFArrayGetCount(plugIn->_factories); 543 while (c-- > 0) _CFPFactoryDisableLocked((_CFPFactoryRef)CFArrayGetValueAtIndex(plugIn->_factories, c)); 544 CFRelease(plugIn->_factories); 545 546 plugIn->_isPlugIn = false; 547 } 548 os_unfair_recursive_lock_unlock(&CFPlugInGlobalDataLock); 549 } 550 551 CF_EXPORT CFTypeID CFPlugInGetTypeID(void) { 552 return CFBundleGetTypeID(); 553 } 554 555 CF_EXPORT CFPlugInRef CFPlugInCreate(CFAllocatorRef allocator, CFURLRef plugInURL) { 556 CFBundleRef bundle = CFBundleCreate(allocator, plugInURL); 557 return (CFPlugInRef)bundle; 558 } 559 560 CF_EXPORT CFBundleRef CFPlugInGetBundle(CFPlugInRef plugIn) { 561 return (CFBundleRef)plugIn; 562 } 563 564 CF_EXPORT void CFPlugInSetLoadOnDemand(CFPlugInRef plugIn, Boolean flag) { 565 _CFPlugInData *plugInData = __CFBundleGetPlugInData(plugIn); 566 if (plugInData->_isPlugIn) { 567 os_unfair_recursive_lock_lock_with_options(&CFPlugInGlobalDataLock, OS_UNFAIR_LOCK_DATA_SYNCHRONIZATION); 568 569 plugInData->_loadOnDemand = flag; 570 if (plugInData->_loadOnDemand && !plugInData->_isDoingDynamicRegistration && plugInData->_instanceCount == 0) 571 { 572 /* Unload now if we can/should. */ 573 /* If we are doing dynamic registration currently, do not unload. The unloading will happen when dynamic registration is done, if necessary. */ 574 os_unfair_recursive_lock_unlock(&CFPlugInGlobalDataLock); 575 576 CFBundleUnloadExecutable(plugIn); 577 } else if (!plugInData->_loadOnDemand) { 578 579 os_unfair_recursive_lock_unlock(&CFPlugInGlobalDataLock); 580 581 /* Make sure we're loaded now. */ 582 CFBundleLoadExecutable(plugIn); 583 } else { 584 os_unfair_recursive_lock_unlock(&CFPlugInGlobalDataLock); 585 } 586 } 587 } 588 589 CF_EXPORT Boolean CFPlugInIsLoadOnDemand(CFPlugInRef plugIn) { 590 if (__CFBundleGetPlugInData(plugIn)->_isPlugIn) { 591 // Checking this is a race no matter what, so don't bother with the lock 592 return __CFBundleGetPlugInData(plugIn)->_loadOnDemand; 593 } else { 594 return false; 595 } 596 } 597 598 CF_PRIVATE void _CFPlugInWillUnload(CFPlugInRef plugIn) { 599 if (__CFBundleGetPlugInData(plugIn)->_isPlugIn) { 600 os_unfair_recursive_lock_lock_with_options(&CFPlugInGlobalDataLock, OS_UNFAIR_LOCK_DATA_SYNCHRONIZATION); 601 602 SInt32 c = CFArrayGetCount(__CFBundleGetPlugInData(plugIn)->_factories); 603 /* First, flush all the function pointers that may be cached by our factories. */ 604 while (c-- > 0) { 605 _CFPFactoryRef factory = (_CFPFactoryRef)CFArrayGetValueAtIndex(__CFBundleGetPlugInData(plugIn)->_factories, c); 606 factory->_func = NULL; 607 } 608 609 os_unfair_recursive_lock_unlock(&CFPlugInGlobalDataLock); 610 } 611 } 612 613 static void _CFPlugInAddPlugInInstanceLocked(CFPlugInRef plugIn) { 614 if (__CFBundleGetPlugInData(plugIn)->_isPlugIn) { 615 if (__CFBundleGetPlugInData(plugIn)->_instanceCount == 0 && __CFBundleGetPlugInData(plugIn)->_loadOnDemand) { 616 // Make sure we are not scheduled for unloading 617 _CFPlugInUnscheduleForUnloading(CFPlugInGetBundle(plugIn)); 618 } 619 __CFBundleGetPlugInData(plugIn)->_instanceCount++; 620 /* Instances also retain the CFBundle */ 621 CFRetain(plugIn); 622 } 623 } 624 625 static void _CFPlugInRemovePlugInInstanceLocked(CFPlugInRef plugIn) { 626 if (__CFBundleGetPlugInData(plugIn)->_isPlugIn) { 627 __CFBundleGetPlugInData(plugIn)->_instanceCount--; 628 if (__CFBundleGetPlugInData(plugIn)->_instanceCount == 0 && __CFBundleGetPlugInData(plugIn)->_loadOnDemand) { 629 // We unload the code lazily because the code that caused this function to be called is probably code from the plugin itself. If we unload now, we will hose things. 630 _CFPlugInScheduleForUnloading(CFPlugInGetBundle(plugIn)); 631 } 632 /* Instances also retain the CFPlugIn */ 633 /* MF:!!! This will cause immediate unloading if it was the last ref on the plugin. */ 634 // Unless there is an 'unload prevention count' 635 CFRelease(plugIn); 636 } 637 } 638 639 static void _CFPlugInIncrementUnloadPreventionLocked(CFPlugInRef plugIn) { 640 if (__CFBundleGetPlugInData(plugIn)->_isPlugIn) { 641 __CFBundleGetPlugInData(plugIn)->_unloadPreventionCount++; 642 } 643 } 644 645 static void _CFPlugInDecrementUnloadPreventionLocked(CFPlugInRef plugIn) { 646 if (__CFBundleGetPlugInData(plugIn)->_isPlugIn) { 647 __CFBundleGetPlugInData(plugIn)->_unloadPreventionCount--; 648 } 649 } 650 651 static void _CFPlugInAddFactoryLocked(CFPlugInRef plugIn, _CFPFactoryRef factory) { 652 if (__CFBundleGetPlugInData(plugIn)->_isPlugIn) CFArrayAppendValue(__CFBundleGetPlugInData(plugIn)->_factories, factory); 653 } 654 655 static void _CFPlugInRemoveFactoryLocked(CFPlugInRef plugIn, _CFPFactoryRef factory) { 656 if (__CFBundleGetPlugInData(plugIn)->_isPlugIn) { 657 SInt32 idx = CFArrayGetFirstIndexOfValue(__CFBundleGetPlugInData(plugIn)->_factories, CFRangeMake(0, CFArrayGetCount(__CFBundleGetPlugInData(plugIn)->_factories)), factory); 658 if (idx >= 0) CFArrayRemoveValueAtIndex(__CFBundleGetPlugInData(plugIn)->_factories, idx); 659 } 660 } 661 662 // MARK: Plugin - Factory 663 664 static void _CFPFactoryDeallocate(CFTypeRef factory); 665 666 const CFRuntimeClass __CFPFactoryClass = { 667 0, 668 "_CFPFactory", 669 NULL, // init 670 NULL, // copy 671 _CFPFactoryDeallocate, 672 NULL, // equal 673 NULL, // hash 674 NULL, // formatting desc 675 NULL, // debug desc 676 }; 677 678 static CFTypeID _CFPFactoryGetTypeID(void) { 679 return _kCFRuntimeIDCFPFactory; 680 } 681 682 static void _CFPFactoryAddToTableLocked(_CFPFactoryRef factory) { 683 CFUUIDRef uuid = factory->_uuid; 684 685 if (!_factoriesByFactoryID) { 686 CFDictionaryValueCallBacks _factoryDictValueCallbacks = {0, NULL, NULL, NULL, NULL}; 687 _factoriesByFactoryID = CFDictionaryCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeDictionaryKeyCallBacks, &_factoryDictValueCallbacks); 688 } 689 CFDictionarySetValue(_factoriesByFactoryID, uuid, factory); 690 691 os_log_debug(_CFBundlePluginLogger(), "Registered factory %{public}@ (%{public}@)", factory, uuid); 692 } 693 694 static void _CFPFactoryRemoveFromTableLocked(_CFPFactoryRef factory) { 695 CFUUIDRef uuid = factory->_uuid; 696 if (uuid && _factoriesByTypeID) CFDictionaryRemoveValue(_factoriesByFactoryID, uuid); 697 698 os_log_debug(_CFBundlePluginLogger(), "Unregistered factory %{public}@ (%{public}@)", factory, uuid); 699 } 700 701 static _CFPFactoryRef _CFPFactoryFindLocked(CFUUIDRef factoryID, Boolean matchOnlyEnabled) { 702 _CFPFactoryRef result = NULL; 703 704 if (_factoriesByFactoryID) { 705 result = (_CFPFactoryRef )CFDictionaryGetValue(_factoriesByFactoryID, factoryID); 706 if (result && matchOnlyEnabled && !result->_enabled) result = NULL; 707 } 708 709 return result; 710 } 711 712 static void _CFPFactoryDeallocate(CFTypeRef ty) { 713 SInt32 c; 714 _CFPFactoryRef factory = (_CFPFactoryRef)ty; 715 716 os_unfair_recursive_lock_lock_with_options(&CFPlugInGlobalDataLock, OS_UNFAIR_LOCK_DATA_SYNCHRONIZATION); 717 718 _CFPFactoryRemoveFromTableLocked(factory); 719 720 if (factory->_plugIn) { 721 _CFPlugInRemoveFactoryLocked(factory->_plugIn, factory); 722 CFRelease(factory->_plugIn); 723 } 724 725 /* Remove all types for this factory. */ 726 c = CFArrayGetCount(factory->_types); 727 while (c-- > 0) _CFPFactoryRemoveTypeLocked(factory, (CFUUIDRef)CFArrayGetValueAtIndex(factory->_types, c)); 728 CFRelease(factory->_types); 729 730 os_unfair_recursive_lock_unlock(&CFPlugInGlobalDataLock); 731 732 if (factory->_funcName) CFRelease(factory->_funcName); 733 if (factory->_uuid) CFRelease(factory->_uuid); 734 } 735 736 static _CFPFactoryRef _CFPFactoryCommonCreateLocked(CFAllocatorRef allocator, CFUUIDRef factoryID) { 737 _CFPFactoryRef factory; 738 uint32_t size; 739 size = sizeof(struct __CFPFactory) - sizeof(CFRuntimeBase); 740 factory = (_CFPFactoryRef)_CFRuntimeCreateInstance(allocator, _CFPFactoryGetTypeID(), size, NULL); 741 if (!factory) return NULL; 742 743 factory->_uuid = (CFUUIDRef)CFRetain(factoryID); 744 factory->_enabled = true; 745 factory->_types = CFArrayCreateMutable(allocator, 0, &kCFTypeArrayCallBacks); 746 747 _CFPFactoryAddToTableLocked(factory); 748 749 return factory; 750 } 751 752 static CFUUIDRef _CFPFactoryCopyFactoryIDLocked(_CFPFactoryRef factory) { 753 CFUUIDRef uuid = factory->_uuid; 754 if (uuid) CFRetain(uuid); 755 return uuid; 756 } 757 758 static CFPlugInRef _CFPFactoryCopyPlugInLocked(_CFPFactoryRef factory) { 759 CFPlugInRef result = factory->_plugIn; 760 if (result) CFRetain(result); 761 return result; 762 } 763 764 static void *__CFPLUGIN_IS_CALLING_OUT_TO_A_FACTORY_FUNCTION__(CFPlugInFactoryFunction f, CFAllocatorRef allocator, CFUUIDRef typeID) { 765 FAULT_CALLBACK((void **)&(f)); 766 void *result = (void *)INVOKE_CALLBACK2(f, allocator, typeID); 767 __asm __volatile__(""); // thwart tail-call optimization 768 return result; 769 } 770 771 static void _CFPFactoryDisableLocked(_CFPFactoryRef factory) { 772 factory->_enabled = false; 773 os_log_debug(_CFBundlePluginLogger(), "Factory %{public}@ has been disabled", factory->_uuid); 774 #if !__clang_analyzer__ 775 CFRelease(factory); 776 #endif 777 } 778 779 static void _CFPFactoryAddTypeLocked(_CFPFactoryRef factory, CFUUIDRef typeID) { 780 /* Add the type to the factory's type list */ 781 CFArrayAppendValue(factory->_types, typeID); 782 783 if (!_factoriesByTypeID) _factoriesByTypeID = CFDictionaryCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); 784 CFMutableArrayRef array = (CFMutableArrayRef)CFDictionaryGetValue(_factoriesByTypeID, typeID); 785 if (!array) { 786 CFArrayCallBacks _factoryArrayCallbacks = {0, NULL, NULL, NULL, NULL}; 787 // Create this from default allocator 788 array = CFArrayCreateMutable(kCFAllocatorSystemDefault, 0, &_factoryArrayCallbacks); 789 CFDictionarySetValue(_factoriesByTypeID, typeID, array); 790 CFRelease(array); 791 } 792 CFArrayAppendValue(array, factory); 793 os_log_debug(_CFBundlePluginLogger(), "Type %{public}@ added to factory %{public}@", typeID, factory->_uuid); 794 } 795 796 static void _CFPFactoryRemoveTypeLocked(_CFPFactoryRef factory, CFUUIDRef typeID) { 797 /* Remove it from the factory's type list */ 798 SInt32 idx = CFArrayGetFirstIndexOfValue(factory->_types, CFRangeMake(0, CFArrayGetCount(factory->_types)), typeID); 799 if (idx >= 0) CFArrayRemoveValueAtIndex(factory->_types, idx); 800 801 /* Remove the factory from the type's list of factories */ 802 if (_factoriesByTypeID) { 803 CFMutableArrayRef array = (CFMutableArrayRef)CFDictionaryGetValue(_factoriesByTypeID, typeID); 804 if (array) { 805 idx = CFArrayGetFirstIndexOfValue(array, CFRangeMake(0, CFArrayGetCount(array)), factory); 806 if (idx >= 0) { 807 CFArrayRemoveValueAtIndex(array, idx); 808 if (CFArrayGetCount(array) == 0) CFDictionaryRemoveValue(_factoriesByTypeID, typeID); 809 } 810 } 811 } 812 os_log_debug(_CFBundlePluginLogger(), "Type %{public}@ removed from factory %{public}@", typeID, factory->_uuid); 813 } 814 815 static Boolean _CFPFactorySupportsTypeLocked(_CFPFactoryRef factory, CFUUIDRef typeID) { 816 SInt32 idx = CFArrayGetFirstIndexOfValue(factory->_types, CFRangeMake(0, CFArrayGetCount(factory->_types)), typeID); 817 return (idx >= 0 ? true : false); 818 } 819 820 /* These methods are called by CFPlugInInstance when an instance is created or destroyed. If a factory's instance count goes to 0 and the factory has been disabled, the factory is destroyed. */ 821 static void _CFPFactoryAddInstanceLocked(_CFPFactoryRef factory) { 822 CFPlugInRef plugin = factory->_plugIn; 823 if (plugin) { 824 _CFPlugInAddPlugInInstanceLocked(plugin); 825 } 826 } 827 828 static void _CFPFactoryRemoveInstanceLocked(_CFPFactoryRef factory) { 829 CFPlugInRef plugin = factory->_plugIn; 830 if (plugin) { 831 _CFPlugInRemovePlugInInstanceLocked(plugin); 832 } 833 } 834 835 #pragma mark - 836 837 /* ===================== Finding factories and creating instances ===================== */ 838 /* For plugIn hosts. */ 839 /* Functions for finding factories to create specific types and actually creating instances of a type. */ 840 841 CF_EXPORT CFArrayRef CFPlugInFindFactoriesForPlugInType(CFUUIDRef typeID) CF_RETURNS_RETAINED { 842 os_unfair_recursive_lock_lock_with_options(&CFPlugInGlobalDataLock, OS_UNFAIR_LOCK_DATA_SYNCHRONIZATION); 843 CFArrayRef array = NULL; 844 if (_factoriesByTypeID) { 845 array = (CFArrayRef)CFDictionaryGetValue(_factoriesByTypeID, typeID); 846 } 847 848 CFMutableArrayRef result = NULL; 849 if (array) { 850 result = CFArrayCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeArrayCallBacks); 851 852 CFIndex c = CFArrayGetCount(array); 853 for (CFIndex i = 0; i < c; i++) { 854 CFUUIDRef factoryId = _CFPFactoryCopyFactoryIDLocked((_CFPFactoryRef)CFArrayGetValueAtIndex(array, i)); 855 if (factoryId) { 856 CFArrayAppendValue(result, factoryId); 857 CFRelease(factoryId); 858 } 859 } 860 } 861 862 os_unfair_recursive_lock_unlock(&CFPlugInGlobalDataLock); 863 os_log_debug(_CFBundlePluginLogger(), "%{public}ld factories found for requested plugin type %{public}@", result ? CFArrayGetCount(result) : 0, typeID); 864 return result; 865 } 866 867 CF_EXPORT CFArrayRef CFPlugInFindFactoriesForPlugInTypeInPlugIn(CFUUIDRef typeID, CFPlugInRef plugIn) CF_RETURNS_RETAINED { 868 os_unfair_recursive_lock_lock_with_options(&CFPlugInGlobalDataLock, OS_UNFAIR_LOCK_DATA_SYNCHRONIZATION); 869 CFArrayRef array = NULL; 870 if (_factoriesByTypeID) { 871 array = (CFArrayRef)CFDictionaryGetValue(_factoriesByTypeID, typeID); 872 } 873 874 875 CFMutableArrayRef result = NULL; 876 if (array) { 877 CFIndex c = CFArrayGetCount(array); 878 result = CFArrayCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeArrayCallBacks); 879 for (CFIndex i = 0; i < c; i++) { 880 _CFPFactoryRef factory = (_CFPFactoryRef)CFArrayGetValueAtIndex(array, i); 881 CFPlugInRef factoryPlugIn = _CFPFactoryCopyPlugInLocked(factory); 882 if (factoryPlugIn == plugIn) { 883 CFUUIDRef factoryId = _CFPFactoryCopyFactoryIDLocked(factory); 884 CFArrayAppendValue(result, factoryId); 885 CFRelease(factoryId); 886 } 887 if (factoryPlugIn) CFRelease(factoryPlugIn); 888 } 889 } 890 891 os_unfair_recursive_lock_unlock(&CFPlugInGlobalDataLock); 892 os_log_debug(_CFBundlePluginLogger(), "%{public}ld factories found for requested plugin type %{public}@ in plugin %{public}@", result ? CFArrayGetCount(result) : 0, typeID, plugIn); 893 return result; 894 } 895 896 // MARK: Plugin - Instance 897 898 static CFStringRef __CFPlugInInstanceCopyDescription(CFTypeRef cf) { 899 /* MF:!!! Implement me */ 900 return CFSTR("Some CFPlugInInstance"); 901 } 902 903 static void __CFPlugInInstanceDeallocate(CFTypeRef cf) { 904 CFPlugInInstanceRef instance = (CFPlugInInstanceRef)cf; 905 906 __CFGenericValidateType(cf, CFPlugInInstanceGetTypeID()); 907 908 os_unfair_recursive_lock_lock_with_options(&CFPlugInGlobalDataLock, OS_UNFAIR_LOCK_DATA_SYNCHRONIZATION); 909 910 if (instance->deallocateInstanceDataFunction) { 911 FAULT_CALLBACK((void **)&(instance->deallocateInstanceDataFunction)); 912 (void)INVOKE_CALLBACK1(instance->deallocateInstanceDataFunction, (void *)(&instance->_instanceData[0])); 913 } 914 915 if (instance->factory) _CFPFactoryRemoveInstanceLocked(instance->factory); 916 917 os_unfair_recursive_lock_unlock(&CFPlugInGlobalDataLock); 918 } 919 920 const CFRuntimeClass __CFPlugInInstanceClass = { 921 0, 922 "CFPlugInInstance", 923 NULL, // init 924 NULL, // copy 925 __CFPlugInInstanceDeallocate, 926 NULL, // equal 927 NULL, // hash 928 NULL, // 929 __CFPlugInInstanceCopyDescription 930 }; 931 932 CFTypeID CFPlugInInstanceGetTypeID(void) { 933 return _kCFRuntimeIDCFPlugInInstance; 934 } 935 936 CF_EXPORT CFPlugInInstanceRef CFPlugInInstanceCreateWithInstanceDataSize(CFAllocatorRef allocator, CFIndex instanceDataSize, CFPlugInInstanceDeallocateInstanceDataFunction deallocateInstanceFunction, CFStringRef factoryName, CFPlugInInstanceGetInterfaceFunction getInterfaceFunction) { 937 CFPlugInInstanceRef instance; 938 UInt32 size; 939 size = sizeof(struct __CFPlugInInstance) + instanceDataSize - sizeof(CFRuntimeBase); 940 instance = (CFPlugInInstanceRef)_CFRuntimeCreateInstance(allocator, CFPlugInInstanceGetTypeID(), size, NULL); 941 if (!instance) return NULL; 942 943 os_unfair_recursive_lock_lock_with_options(&CFPlugInGlobalDataLock, OS_UNFAIR_LOCK_DATA_SYNCHRONIZATION); 944 945 instance->factory = _CFPFactoryFindLocked((CFUUIDRef)factoryName, true); 946 if (instance->factory) _CFPFactoryAddInstanceLocked(instance->factory); 947 instance->getInterfaceFunction = getInterfaceFunction; 948 instance->deallocateInstanceDataFunction = deallocateInstanceFunction; 949 950 os_unfair_recursive_lock_unlock(&CFPlugInGlobalDataLock); 951 952 return instance; 953 } 954 955 CF_EXPORT Boolean CFPlugInInstanceGetInterfaceFunctionTable(CFPlugInInstanceRef instance, CFStringRef interfaceName, void **ftbl) { 956 void *myFtbl; 957 Boolean result = false; 958 959 if (instance->getInterfaceFunction) { 960 FAULT_CALLBACK((void **)&(instance->getInterfaceFunction)); 961 result = INVOKE_CALLBACK3(instance->getInterfaceFunction, instance, interfaceName, &myFtbl) ? true : false; 962 } 963 if (ftbl) *ftbl = (result ? myFtbl : NULL); 964 return result; 965 } 966 967 CF_EXPORT CFStringRef CFPlugInInstanceGetFactoryName(CFPlugInInstanceRef instance) { 968 os_unfair_recursive_lock_lock_with_options(&CFPlugInGlobalDataLock, OS_UNFAIR_LOCK_DATA_SYNCHRONIZATION); 969 970 // This function leaks, but it's the only safe way to access the factory name (on 10.8 or later). 971 // On 10.9 we added the CF_RETURNS_RETAINED annotation to the header. 972 CFUUIDRef factoryId = _CFPFactoryCopyFactoryIDLocked(instance->factory); 973 974 os_unfair_recursive_lock_unlock(&CFPlugInGlobalDataLock); 975 976 return (CFStringRef)factoryId; 977 } 978 979 CF_EXPORT void *CFPlugInInstanceGetInstanceData(CFPlugInInstanceRef instance) { 980 return (void *)(&instance->_instanceData[0]); 981 }