Skip to content

Commit

Permalink
feat: add App-launch-lifecycle
Browse files Browse the repository at this point in the history
  • Loading branch information
YueChen-C committed Feb 16, 2023
1 parent bcd093a commit 2306101
Show file tree
Hide file tree
Showing 7 changed files with 391 additions and 3 deletions.
14 changes: 14 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ python version: 3.7 +
- [x] Dump core profile stack snapshot
- [x] Analyze the core profile data stream
- [x] Get Metal GPU Counters
- [x] Get App Launch Lifecycle


### Other
Expand Down Expand Up @@ -167,6 +168,19 @@ $ instruments gpu_counters
15.132907 GPU Write Bandwidth 1.25
```

#### Get App Launch Lifecycle
```bash
$ instruments app_lifecycle -b cn.rongcloud.im
31.20 ms Initializing-System Interface Initialization (Dyld init)
14.33 ms Initializing-Static Runtime Initialization
35.68 ms Launching-UIKit Initialization
810.46 us Launching-UIKit Scene Creation
100.64 ms Launching-didFinishLaunchingWithOptions()
2.91 ms Launching-UIKit Scene Creation
21.85 ms Launching-Initial Frame Rendering
App Thread Process ID:6506076, Total Time:207.41 ms
```

### Other
#### Profiles & Device Management

Expand Down
13 changes: 13 additions & 0 deletions README_CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ python 版本: 3.7 +
- [x] 解析内核数据流
- [x] 获取 iOS GPU Counters
- [x] 设置虚拟位置信息
- [x] 获取 APP 启动时间


### 其他功能列表
Expand Down Expand Up @@ -169,6 +170,18 @@ $ instruments gup_counters
15.132907 GPU Write Bandwidth 1.25
```

#### 获取 App 启动时间以及生命周期
```bash
$ instruments app_lifecycle -b cn.rongcloud.im
31.20 ms Initializing-System Interface Initialization (Dyld init)
14.33 ms Initializing-Static Runtime Initialization
35.68 ms Launching-UIKit Initialization
810.46 us Launching-UIKit Scene Creation
100.64 ms Launching-didFinishLaunchingWithOptions()
2.91 ms Launching-UIKit Scene Creation
21.85 ms Launching-Initial Frame Rendering
App Thread Process ID:6506076, Total Time:207.41 ms
```

### 其他功能示例
#### 描述文件管理
Expand Down
60 changes: 60 additions & 0 deletions demo/instrument_demo/app_lifecycle.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import time
import uuid

from ios_device.cli.base import InstrumentDeviceInfo
from ios_device.servers.Instrument import InstrumentServer
from ios_device.util.lifecycle import AppLifeCycle
from ios_device.util.dtx_msg import RawObj
from ios_device.util.exceptions import InstrumentRPCParseError
from ios_device.util.kperf_data import KperfData, KdBufParser


def app_launch_lifecyle(rpc, bundleid):
traceCodesFile = InstrumentDeviceInfo(rpc).traceCodesFile()
Kperf = KperfData(traceCodesFile)
machTimeInfo = rpc.call("com.apple.instruments.server.services.deviceinfo", "machTimeInfo").selector
usecs_since_epoch = rpc.lockdown.get_value(key='TimeIntervalSince1970') * 1000000
LifeCycle = AppLifeCycle(machTimeInfo, usecs_since_epoch)

def demo(data):
for event in Kperf.to_dict(data):
if isinstance(event, KdBufParser):
_, process_name = Kperf.threads_pids.get(event.tid, (None, None))
if event.class_code in (0x1f, 0x2b, 0x31) and process_name not in ('SpringBoard',):
LifeCycle.decode_app_lifecycle(event, process_name or event.tid)
if event.debug_id == 835321862:
LifeCycle.format_str()

def on_graphics_message(res):
if type(res.selector) is InstrumentRPCParseError:
demo(res.selector.data)

rpc.register_channel_callback("com.apple.instruments.server.services.coreprofilesessiontap", on_graphics_message)
rpc.call("com.apple.instruments.server.services.coreprofilesessiontap", "setConfig:",
{'rp': 100,
'bm': 1,
'tc': [{'kdf2': {735576064, 835321856, 735838208, 730267648,
520552448},
'csd': 128,
'tk': 3,
'ta': [[3], [0], [2], [1, 1, 0]],
'uuid': str(uuid.uuid4()).upper()}],
})
rpc.call("com.apple.instruments.server.services.coreprofilesessiontap", "start")
channel = "com.apple.instruments.server.services.processcontrol"
pid = rpc.call(channel, 'launchSuspendedProcessWithDevicePath:bundleIdentifier:environment:arguments:options:',
'',
bundleid,
{'OS_ACTIVITY_DT_MODE': '1', 'HIPreventRefEncoding': '1', 'DYLD_PRINT_TO_STDERR': '1'}, [],
{'StartSuspendedKey': 0}).selector
print(f'start {bundleid} pid:{pid}')

time.sleep(1000)
rpc.call("com.apple.instruments.server.services.coreprofilesessiontap", "stop")
rpc.stop()


if __name__ == '__main__':
rpc = InstrumentServer().init()
app_launch_lifecyle(rpc, 'cn.rongcloud.im')
rpc.stop()
2 changes: 1 addition & 1 deletion ios_device/__version__.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
__version__ = "2.3.1"
__version__ = "2.3.2"
54 changes: 52 additions & 2 deletions ios_device/cli/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,12 @@
from ios_device.servers.house_arrest import HouseArrestService
from ios_device.servers.testmanagerd import TestManagerdLockdown
from ios_device.util import Log
from ios_device.util.lifecycle import AppLifeCycle
from ios_device.util.bpylist2 import NSUUID, NSURL, XCTestConfiguration
from ios_device.util.bpylist2 import archive
from ios_device.util.dtx_msg import RawObj, RawInt32sl, RawInt64sl
from ios_device.util.exceptions import InstrumentRPCParseError
from ios_device.util.gpu_decode import JSEvn, TraceData
from ios_device.util.kperf_data import KperfData
from ios_device.util.kperf_data import KperfData, KdBufParser
from ios_device.util.lockdown import LockdownClient
from ios_device.util.variables import InstrumentsService, LOG

Expand Down Expand Up @@ -596,3 +596,53 @@ def on_graphics_message(res):
pass
self.instruments.call("com.apple.instruments.server.services.coreprofilesessiontap", "stop")
self.instruments.stop()

def app_launch_lifecycle(self, bundleid, stopSignal: threading.Event = threading.Event()):
traceCodesFile = self.device_info.traceCodesFile()
Kperf = KperfData(traceCodesFile)
machTimeInfo = self.instruments.call("com.apple.instruments.server.services.deviceinfo",
"machTimeInfo").selector
usecs_since_epoch = self.lockdown.get_value(key='TimeIntervalSince1970') * 1000000
LifeCycle = AppLifeCycle(machTimeInfo, usecs_since_epoch)

def demo(data):
for event in Kperf.to_dict(data):
if isinstance(event, KdBufParser):
_, process_name = Kperf.threads_pids.get(event.tid, (None, None))
if event.class_code in (0x1f, 0x2b, 0x31) and process_name not in ('SpringBoard',):
LifeCycle.decode_app_lifecycle(event, process_name or event.tid)
if event.debug_id == 835321862:
LifeCycle.format_str()

def on_graphics_message(res):
if type(res.selector) is InstrumentRPCParseError:
demo(res.selector.data)

self.instruments.register_channel_callback("com.apple.instruments.server.services.coreprofilesessiontap",
on_graphics_message)
self.instruments.call("com.apple.instruments.server.services.coreprofilesessiontap", "setConfig:",
{'rp': 100,
'bm': 1,
'tc': [{'kdf2': {735576064, 835321856, 735838208, 730267648,
520552448},
'csd': 128,
'tk': 3,
'ta': [[3], [0], [2], [1, 1, 0]],
'uuid': str(uuid.uuid4()).upper()}],
})
self.instruments.call("com.apple.instruments.server.services.coreprofilesessiontap", "start")
channel = "com.apple.instruments.server.services.processcontrol"
pid = self.instruments.call(channel,
'launchSuspendedProcessWithDevicePath:bundleIdentifier:environment:arguments:options:',
'',
bundleid,
{'OS_ACTIVITY_DT_MODE': '1',
'HIPreventRefEncoding': '1',
'DYLD_PRINT_TO_STDERR': '1'}, [],
{'StartSuspendedKey': 0}).selector
print(f'start {bundleid} pid:{pid} [!] wait a few seconds, being analysed...')

while not stopSignal.wait(1):
pass
self.instruments.call("com.apple.instruments.server.services.coreprofilesessiontap", "stop")
self.instruments.stop()
8 changes: 8 additions & 0 deletions ios_device/cli/instruments.py
Original file line number Diff line number Diff line change
Expand Up @@ -410,3 +410,11 @@ def dropped_message(res):
mach_time_factor = machTimeInfo[1] / machTimeInfo[2]
data = rpc.gpu_counters(callback=dropped_message, stopSignal=stopSignal)
js_env.dump_trace(TraceData(*data[0]))


@instruments.command('app_lifecycle', cls=Command)
@click.option('-b', '--bundle_id', default=None, help='Process app bundleId')
def cmd_app_lifecycle(udid, network, format, bundle_id):
with InstrumentsBase(udid=udid, network=network) as rpc:
rpc.app_launch_lifecycle(bundle_id)

Loading

0 comments on commit 2306101

Please sign in to comment.