1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
|
#!/usr/bin/env python3
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at https://mozilla.org/MPL/2.0/.
"""
A script to set up startup profiling with the Firefox Profiler. See
https://profiler.firefox.com/docs/#/./guide-remote-profiling?id=startup-profiling
for more information.
"""
import argparse
import os
import tempfile
from subprocess import run
PATH_PREFIX = "/data/local/tmp"
PROD_FENIX = "fenix"
PROD_GVE = "geckoview_example"
PRODUCTS = [PROD_FENIX, PROD_GVE]
GV_CONFIG = b"""env:
MOZ_PROFILER_STARTUP: 1
MOZ_PROFILER_STARTUP_INTERVAL: 5
MOZ_PROFILER_STARTUP_FEATURES: js,stackwalk,leaf,screenshots,ipcmessages,java,cpu
MOZ_PROFILER_STARTUP_FILTERS: GeckoMain,Compositor,Renderer,IPDL Background
"""
def parse_args():
p = argparse.ArgumentParser(
description=(
"Easily enable start up profiling using the Firefox Profiler. Finish capturing the profile in "
"about:debugging on desktop. See "
"https://profiler.firefox.com/docs/#/./guide-remote-profiling?id=startup-profiling for "
"details."
)
)
p.add_argument(
"command",
choices=["activate", "deactivate"],
help=(
"whether to activate or deactive start up "
"profiling for the given release channel"
),
)
p.add_argument(
"release_channel",
choices=["nightly", "beta", "release", "debug"],
help=(
"the release channel to "
"change the startup profiling state of the command on"
),
)
p.add_argument(
"-p",
"--product",
choices=PRODUCTS,
default=PROD_FENIX,
help="which product to work on",
)
return p.parse_args()
def push(id, filename):
config = tempfile.NamedTemporaryFile(delete=False)
try:
# I think the file needs to be closed to save its contents for adb push to
# work correctly so we close it here and later delete it manually.
with config.file as f:
f.write(GV_CONFIG)
print("Pushing {} to device.".format(filename))
run(["adb", "push", config.name, os.path.join(PATH_PREFIX, filename)])
run(["adb", "shell", "am", "set-debug-app", "--persistent", id])
print(
"\nStartup profiling enabled on all future start ups, possibly even after reinstall."
)
print("Call script with `deactivate` to disable it.")
print(
"DISABLE 'Remote debugging via USB' IN THE APP SETTINGS BEFORE STARTING THE APP & RE-ENABLE TO CAPTURE THE PROFILE.",
"This avoids the additional overhead added when 'Remote debugging via USB' is enabled during start up.",
sep=os.linesep,
)
finally:
os.remove(config.name)
def remove(filename):
print("Removing {} from device.".format(filename))
run(["adb", "shell", "rm", PATH_PREFIX + "/" + filename])
run(["adb", "shell", "am", "clear-debug-app"])
def convert_channel_to_id(product, channel):
if product == PROD_FENIX:
mapping = {
"release": "org.mozilla.firefox",
"beta": "org.mozilla.firefox_beta",
"nightly": "org.mozilla.fenix",
"debug": "org.mozilla.fenix.debug",
}
return mapping[channel]
elif product == PROD_GVE:
return "org.mozilla.geckoview_example"
def main():
args = parse_args()
id = convert_channel_to_id(args.product, args.release_channel)
filename = id + "-geckoview-config.yaml"
if args.command == "activate":
push(id, filename)
elif args.command == "deactivate":
remove(filename)
if __name__ == "__main__":
main()
|