Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

Optimize search for the default bundle #39975

Merged
merged 2 commits into from
Mar 7, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 46 additions & 2 deletions shell/platform/darwin/ios/framework/Source/FlutterDartProject.mm
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,50 @@

static const char* kApplicationKernelSnapshotFileName = "kernel_blob.bin";

// Finds a bundle with the named `bundleID` within `searchURL`.
//
// Returns `nil` if the bundle cannot be found or if errors are encountered.
NSBundle* FLTFrameworkBundleInternal(NSString* bundleID, NSURL* searchURL) {
NSDirectoryEnumerator<NSURL*>* frameworkEnumerator = [NSFileManager.defaultManager
enumeratorAtURL:searchURL
includingPropertiesForKeys:nil
options:NSDirectoryEnumerationSkipsSubdirectoryDescendants |
NSDirectoryEnumerationSkipsHiddenFiles
// Skip directories where errors are encountered.
errorHandler:nil];

for (NSURL* candidate in frameworkEnumerator) {
NSBundle* bundle = [NSBundle bundleWithURL:candidate];
if ([bundle.bundleIdentifier isEqualToString:bundleID]) {
return bundle;
}
}
return nil;
}

// Finds a bundle with the named `bundleID`.
//
// `+[NSBundle bundleWithIdentifier:]` is slow, and can take in the order of
// tens of milliseconds in a minimal flutter app, and closer to 100 milliseconds
// in a medium sized Flutter app on an iPhone 13. It is likely that the slowness
// comes from having to traverse and load all bundles known to the process.
// Using `+[NSBundle allframeworks]` and filtering also suffers from the same
// problem.
//
// This implementation is an optimization to first limit the search space to
// `+[NSBundle privateFrameworksURL]` of the main bundle, which is usually where
// frameworks used by this file are placed. If the desired bundle cannot be
// found here, the implementation falls back to
// `+[NSBundle bundleWithIdentifier:]`.
NS_INLINE NSBundle* FLTFrameworkBundleWithIdentifier(NSString* bundleID) {
NSBundle* bundle = FLTFrameworkBundleInternal(bundleID, NSBundle.mainBundle.privateFrameworksURL);
if (bundle != nil) {
return bundle;
}
// Fallback to slow implementation.
return [NSBundle bundleWithIdentifier:bundleID];
}

flutter::Settings FLTDefaultSettingsForBundle(NSBundle* bundle) {
auto command_line = flutter::CommandLineFromNSProcessInfo();

Expand All @@ -46,7 +90,7 @@

bool hasExplicitBundle = bundle != nil;
if (bundle == nil) {
bundle = [NSBundle bundleWithIdentifier:[FlutterDartProject defaultBundleIdentifier]];
bundle = FLTFrameworkBundleWithIdentifier([FlutterDartProject defaultBundleIdentifier]);
}
if (bundle == nil) {
bundle = mainBundle;
Expand Down Expand Up @@ -309,7 +353,7 @@ - (instancetype)initWithSettings:(const flutter::Settings&)settings {

+ (NSString*)flutterAssetsName:(NSBundle*)bundle {
if (bundle == nil) {
bundle = [NSBundle bundleWithIdentifier:[FlutterDartProject defaultBundleIdentifier]];
bundle = FLTFrameworkBundleWithIdentifier([FlutterDartProject defaultBundleIdentifier]);
}
if (bundle == nil) {
bundle = [NSBundle mainBundle];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,19 @@ - (void)testLeakDartVMSettingsAreCorrectlyParsed {
XCTAssertEqual(settings.leak_vm, NO);
}

- (void)testFLTFrameworkBundleInternalWhenBundleIsNotPresent {
NSBundle* found =
FLTFrameworkBundleInternal(@"doesNotExist", NSBundle.mainBundle.privateFrameworksURL);
XCTAssertNil(found);
}

- (void)testFLTFrameworkBundleInternalWhenBundleIsPresent {
NSString* presentBundleID = @"io.flutter.flutter";
NSBundle* found =
FLTFrameworkBundleInternal(presentBundleID, NSBundle.mainBundle.privateFrameworksURL);
XCTAssertNotNil(found);
}

- (void)testEnableImpellerSettingIsCorrectlyParsed {
// The FLTEnableImpeller's value is defined in Info.plist
NSBundle* mainBundle = [NSBundle mainBundle];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@

NS_ASSUME_NONNULL_BEGIN

NSBundle* FLTFrameworkBundleInternal(NSString* bundleID, NSURL* searchURL);

flutter::Settings FLTDefaultSettingsForBundle(NSBundle* bundle = nil);

@interface FlutterDartProject ()
Expand Down