LaunchScreen Analysis

tl;dr

After clicking App icon, iOS system’s desktop SpringBoard will first create LaunchScreen, then create App’s corresponding process. Then can think: LaunchScreen’s loading doesn’t occupy App process’s own perceived startup time. LaunchScreen is SpringBoard showing to users in advance before process startup for user experience.

Of course strictly speaking, LaunchScreen’s loading occupies system CPU and other resources, also has certain impact on App’s startup time.

Below is brief exploration process.

Environment

iOS 11.3.1 Jailbroken Jailbreak steps see: https://everettjf.github.io/2018/08/30/ios1131-jailbreak-tutorial/ Other jailbroken phones can also complete steps below.

Small ad here: To purchase jailbreakable phone can contact WeChat “467444”, I just bought an iPhone6S 11.3.1 from him, currently using everything normal.

Basics

Steps use basics below, can reference these three links when encountering problems:

Start

Phone open to desktop, connect to computer, open an empty project, Xcode attach to SpringBoard, print ViewControllers and Views (chisel’s pvc and pviews commands).

Can see just a few key information: SBIconController SBHomeScreenViewController SBRootIconListView SBIconView

class-dump SpringBoard browse.

Through SBIconView can see this Delegate’s - (void)iconTapped:(SBIconView *)arg1;

Print delegate

Know SBIconController is delegate, indeed saw implementation in header file.

IDA open SpringBoard, look at iconTapped implementation:

Header file search prepareToLaunchTappedIcon:completionHandler:

IDA again

From sub_10017A874 above,

Look at _launchFromIconView

-[[FBWorkspaceEventQueue sharedInstance] executeOrAppendEvent:]

FrontBoard

Network search FBWorkspaceEventQueue can immediately know, now at FrontBoard.framework.

Find in this directory /Users/everettjf/Library/Developer/Xcode/iOS DeviceSupport/11.3.1 (15E302)/Symbols/System/Library/PrivateFrameworks

IDA separately analyze FrontBoard,

Many code can’t analyze. Then lldb debug.

Continue Debugging

First symbol breakpoint

Find those unrecognized BL instructions, address breakpoint:

Looks like arrayWithObjects, then pass to executeOrInsertEvents:atPosition:

Continue

Still many unrecognized, address breakpoint one by one, repeat po $x0 , p (char*)$x1 , po $x2

<FBSynchronizedTransactionGroup: 0x1c0574c40>
    Completed: NO
    Milestones pending: 
        synchronizedCommit
    Audit history: 
        TIME: 22:42:45.524; DESCRIPTION: Life assertion taken for reason: beginning
        TIME: 22:42:45.524; DESCRIPTION: State changed from 'Initial' to 'Working'
        TIME: 22:42:45.524; DESCRIPTION: Life assertion removed for reason: beginning
        TIME: 22:42:45.627; DESCRIPTION: Commit preconditions satisfied.
        TIME: 22:42:45.627; DESCRIPTION: Milestones added: synchronizedCommit
        TIME: 22:42:45.627; DESCRIPTION: Using synchronization delegate: <SBSceneLayoutWorkspaceTransaction: 0x151d125d0>
    Concurrent child transactions: 
        <SBApplicationSceneUpdateTransaction: 0x151c85a70>
            Completed: NO
            Application: <SBDeviceApplicationSceneEntity: 0x1c0c9a810; ID: com.meituan.imeituan; layoutRole: primary>
            SceneID: com.meituan.imeituan
            Display: Main
            Launch Suspended: NO
            Milestones pending: 
                synchronizedCommit
            Audit history: 
                TIME: 22:42:45.524; DESCRIPTION: Life assertion taken for reason: beginning
                TIME: 22:42:45.524; DESCRIPTION: State changed from 'Initial' to 'Working'
                TIME: 22:42:45.524; DESCRIPTION: Life assertion removed for reason: beginning
                TIME: 22:42:45.626; DESCRIPTION: Beginning scene updates.
                TIME: 22:42:45.626; DESCRIPTION: Adding child transaction: <FBUpdateSceneTransaction: 0x1c41beae0>
                TIME: 22:42:45.627; DESCRIPTION: Commit preconditions satisfied.
                TIME: 22:42:45.627; DESCRIPTION: Milestones added: synchronizedCommit
                TIME: 22:42:45.627; DESCRIPTION: Using synchronization delegate: <FBSynchronizedTransactionGroup: 0x1c0574c40>
            Concurrent child transactions: 
                <FBApplicationProcessLaunchTransaction: 0x1c0388c90>
                    Completed: NO
                    Process: <FBApplicationProcess: 0x14f684580; imeituan (com.meituan.imeituan); pid: 1168>
                    Milestones pending: 
                        processWillBeginLaunching
                        processDidFinishLaunching
                    Audit history: 
                        TIME: 22:42:45.524; DESCRIPTION: Life assertion taken for reason: beginning
                        TIME: 22:42:45.524; DESCRIPTION: State changed from 'Initial' to 'Working'
                        TIME: 22:42:45.524; DESCRIPTION: Milestones added: processWillBeginLaunching
                        TIME: 22:42:45.524; DESCRIPTION: Life assertion removed for reason: beginning
                        TIME: 22:42:45.626; DESCRIPTION: Milestones added: processDidFinishLaunching
                    Concurrent child transactions: (none)
                    Serial child transactions: (none)
                <FBUpdateSceneTransaction: 0x1c41beae0>
                    Completed: NO
                    SceneID: com.meituan.imeituan
                    Scene Visibility: Foreground
                    Wait for Commit: YES
                    Milestones pending: 
                        synchronizedCommit
                    Audit history: 
                        TIME: 22:42:45.626; DESCRIPTION: Life assertion taken for reason: beginning
                        TIME: 22:42:45.627; DESCRIPTION: State changed from 'Initial' to 'Working'
                        TIME: 22:42:45.627; DESCRIPTION: Milestones added: synchronizedCommit
                    Concurrent child transactions: (none)
                    Serial child transactions: (none)
            Serial child transactions: (none)
    Serial child transactions: (none)
graph-base64-encoded: 

…. Omitted here ….

Finally

Finally found -[FBSynchronizedTransactionGroup _performSynchronizedCommit:] and -[FBApplicationUpdateScenesTransaction _performSynchronizedCommit:] and +[FBSceneManager synchronizeChanges:]

Temporarily Stop

OK stop for now.

Write tweak

After various hooks, finally discovered, if we hook -[FBSynchronizedTransactionGroup _performSynchronizedCommit:], directly return.

Or -[FBSynchronizedTransactionGroup addSynchronizedTransaction:] directly return.

Can both achieve an effect:

  1. LaunchScreen started, but doesn’t disappear.
  2. App’s process doesn’t exist. (Can’t see App’s process in ps ax)

Conclusion

Then we can think:

After clicking App icon, iOS system’s desktop SpringBoard will first create LaunchScreen, then create App’s corresponding process. Then can think: LaunchScreen’s loading doesn’t occupy App process’s own perceived startup time. LaunchScreen is SpringBoard showing to users in advance before process startup for user experience.

Code

https://github.com/everettjf/Yolo/tree/master/BukuzaoArchive/sample/AppFrequencyReport/AppFrequencyReport/AppFrequencyReport.xm

dyld_shared_cache

Actually these BL IDA can normally recognize, just because I only analyzed FrontBoard one dynamic library. Actually can directly analyze /System/Library/Caches/com.apple.dyld/dyld_shared_cache_arm64 , but rumor says analyzing this needs 30+ GB space. I also tried using IDA and Hopper to analyze, but because too large, various postures all can’t finish analyzing, either error, or stuck.

But currently OK, got this conclusion. Will continue exploring when there’s time.

Small Fragment

Still these unrecognized BL

step-in after is like this

step-in again is like this

Through two jumps, seems this is dyld_shared_cache’s characteristic, haven’t deeply searched materials. Looks like this can save dynamic binding process.

This is why fishhook can’t hook UIKit and other system libraries’ objc_msgSend.

Will continue researching when there’s time :)

Summary

Actually originally wanted to continue exploring to App process creation flow, how to notify launchd to start App process, but dyld_shared_cache always can’t finish analyzing, just temporarily like this, continue forward, will review when there’s time.

Interesting, but also quite time-consuming~

Welcome to follow subscription account “Client Technology Review”: happyhackingstudio