Kea2-python 1.0.6b0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of Kea2-python might be problematic. Click here for more details.

Files changed (52) hide show
  1. kea2/__init__.py +3 -0
  2. kea2/absDriver.py +56 -0
  3. kea2/adbUtils.py +554 -0
  4. kea2/assets/config_version.json +16 -0
  5. kea2/assets/fastbot-thirdpart.jar +0 -0
  6. kea2/assets/fastbot_configs/abl.strings +2 -0
  7. kea2/assets/fastbot_configs/awl.strings +3 -0
  8. kea2/assets/fastbot_configs/max.config +7 -0
  9. kea2/assets/fastbot_configs/max.fuzzing.strings +699 -0
  10. kea2/assets/fastbot_configs/max.schema.strings +1 -0
  11. kea2/assets/fastbot_configs/max.strings +3 -0
  12. kea2/assets/fastbot_configs/max.tree.pruning +27 -0
  13. kea2/assets/fastbot_configs/teardown.py +18 -0
  14. kea2/assets/fastbot_configs/widget.block.py +38 -0
  15. kea2/assets/fastbot_libs/arm64-v8a/libfastbot_native.so +0 -0
  16. kea2/assets/fastbot_libs/armeabi-v7a/libfastbot_native.so +0 -0
  17. kea2/assets/fastbot_libs/x86/libfastbot_native.so +0 -0
  18. kea2/assets/fastbot_libs/x86_64/libfastbot_native.so +0 -0
  19. kea2/assets/framework.jar +0 -0
  20. kea2/assets/kea2-thirdpart.jar +0 -0
  21. kea2/assets/monkeyq.jar +0 -0
  22. kea2/assets/quicktest.py +126 -0
  23. kea2/cli.py +320 -0
  24. kea2/fastbotManager.py +267 -0
  25. kea2/fastbotx/ActivityTimes.py +52 -0
  26. kea2/fastbotx/ReuseEntry.py +74 -0
  27. kea2/fastbotx/ReuseModel.py +63 -0
  28. kea2/fastbotx/__init__.py +7 -0
  29. kea2/fbm_parser.py +871 -0
  30. kea2/fs_lock.py +131 -0
  31. kea2/kea2_api.py +166 -0
  32. kea2/keaUtils.py +1112 -0
  33. kea2/kea_launcher.py +319 -0
  34. kea2/logWatcher.py +92 -0
  35. kea2/mixin.py +22 -0
  36. kea2/report/__init__.py +0 -0
  37. kea2/report/bug_report_generator.py +793 -0
  38. kea2/report/mixin.py +482 -0
  39. kea2/report/report_merger.py +797 -0
  40. kea2/report/templates/bug_report_template.html +3876 -0
  41. kea2/report/templates/merged_bug_report_template.html +3333 -0
  42. kea2/report/utils.py +10 -0
  43. kea2/resultSyncer.py +65 -0
  44. kea2/u2Driver.py +610 -0
  45. kea2/utils.py +184 -0
  46. kea2/version_manager.py +102 -0
  47. kea2_python-1.0.6b0.dist-info/METADATA +447 -0
  48. kea2_python-1.0.6b0.dist-info/RECORD +52 -0
  49. kea2_python-1.0.6b0.dist-info/WHEEL +5 -0
  50. kea2_python-1.0.6b0.dist-info/entry_points.txt +2 -0
  51. kea2_python-1.0.6b0.dist-info/licenses/LICENSE +16 -0
  52. kea2_python-1.0.6b0.dist-info/top_level.txt +1 -0
kea2/fastbotManager.py ADDED
@@ -0,0 +1,267 @@
1
+ import itertools
2
+ import requests
3
+
4
+ from time import sleep
5
+ from dataclasses import asdict
6
+ from pathlib import Path
7
+
8
+ from retry import retry
9
+ from retry.api import retry_call
10
+ from uiautomator2.core import HTTPResponse, _http_request
11
+ from packaging.version import parse as parse_version
12
+
13
+ from .utils import getLogger, getProjectRoot
14
+ from .adbUtils import ADBDevice, ADBStreamShell_V2
15
+
16
+
17
+ from typing import IO, TYPE_CHECKING, Dict
18
+ if TYPE_CHECKING:
19
+ from .keaUtils import Options, PropertyExecutionInfo
20
+
21
+
22
+ logger = getLogger(__name__)
23
+
24
+
25
+ class FastbotManager:
26
+ def __init__(self, options: "Options", log_file: str):
27
+ self.options:"Options" = options
28
+ self.log_file: str = log_file
29
+ self.port = None
30
+ self.thread = None
31
+ self._device_output_dir = None
32
+ ADBDevice.setDevice(options.serial, options.transport_id)
33
+ self.dev = ADBDevice()
34
+ self.android_release = parse_version(self.dev.getprop("ro.build.version.release"))
35
+ self.executed_prop = False
36
+
37
+ def _activateFastbot(self) -> ADBStreamShell_V2:
38
+ """
39
+ activate fastbot.
40
+ :params: options: the running setting for fastbot
41
+ :params: port: the listening port for script driver
42
+ :return: the fastbot daemon thread
43
+ """
44
+
45
+ self._push_libs()
46
+ t = self._startFastbotService()
47
+ logger.info("Running Fastbot...")
48
+ return t
49
+
50
+ def check_alive(self):
51
+ """
52
+ check if the script driver and proxy server are alive.
53
+ """
54
+ def _check_alive_request():
55
+ _http_request(dev=self.dev, device_port=8090, method="GET", path="/ping")
56
+
57
+ try:
58
+ logger.info("Connecting to fastbot server...")
59
+ retry_call(_check_alive_request, tries=10, delay=2, logger=logger)
60
+ logger.info("Connected to fastbot server.")
61
+ except requests.ConnectionError:
62
+ raise RuntimeError("Failed to connect fastbot")
63
+
64
+ def request(self, method: str, path: str, data: Dict=None, timeout: int=10) -> HTTPResponse:
65
+ return _http_request(self.dev, 8090, method, path, data, timeout)
66
+
67
+ @retry(Exception, tries=2, delay=2)
68
+ def init(self, options: "Options", stamp):
69
+ post_data = {
70
+ "takeScreenshots": options.take_screenshots,
71
+ "preFailureScreenshots": options.pre_failure_screenshots,
72
+ "postFailureScreenshots": options.post_failure_screenshots,
73
+ "logStamp": stamp,
74
+ "deviceOutputRoot": options.device_output_root,
75
+ }
76
+ r = _http_request(
77
+ self.dev,
78
+ device_port=8090,
79
+ method="POST",
80
+ path="/init",
81
+ data=post_data
82
+ )
83
+ print(f"[INFO] Init fastbot: {post_data}", flush=True)
84
+ import re
85
+ self._device_output_dir = re.match(r"outputDir:(.+)", r.text).group(1)
86
+ print(f"[INFO] Fastbot initiated. outputDir: {r.text}", flush=True)
87
+
88
+ @retry(Exception, tries=2, delay=2)
89
+ def stepMonkey(self, monkeyStepInfo):
90
+ r = self.request(
91
+ method="POST",
92
+ path="/stepMonkey",
93
+ data=monkeyStepInfo
94
+ )
95
+ return r.json()["result"]
96
+
97
+ @retry(Exception, tries=2, delay=2)
98
+ def stopMonkey(self):
99
+ """
100
+ send a stop monkey request to the server.
101
+ """
102
+ r = self.request(
103
+ method="GET",
104
+ path="/stopMonkey",
105
+ )
106
+
107
+ print(f"[Server INFO] {r.text}", flush=True)
108
+
109
+ @retry(Exception, tries=2, delay=2)
110
+ def logScript(self, execution_info: "PropertyExecutionInfo"):
111
+ r = self.request(
112
+ method="POST",
113
+ path="/logScript",
114
+ data={
115
+ "propName": execution_info.propName,
116
+ "startStepsCount": execution_info.startStepsCount,
117
+ "state": execution_info.state,
118
+ }
119
+ )
120
+ res = r.text
121
+ if res != "OK":
122
+ print(f"[ERROR] Error when logging script: {execution_info}", flush=True)
123
+
124
+ @retry(Exception, tries=2, delay=2)
125
+ def dumpHierarchy(self):
126
+ sleep(self.options.throttle / 1000)
127
+ r = self.request(
128
+ method="GET",
129
+ path="/dumpHierarchy",
130
+ )
131
+ return r.json()['result']
132
+
133
+ @retry(Exception, tries=2, delay=2)
134
+ def sendInfo(self, info: str):
135
+ r = self.request(
136
+ method="POST",
137
+ path="/sendInfo",
138
+ data=info
139
+ )
140
+
141
+ @property
142
+ def device_output_dir(self):
143
+ return self._device_output_dir
144
+
145
+ def _push_libs(self):
146
+ logger.info("Pushing Fastbot libraries to device...")
147
+ cur_dir = Path(__file__).parent
148
+ self.dev.sync.push(
149
+ Path.joinpath(cur_dir, "assets/monkeyq.jar"),
150
+ "/sdcard/monkeyq.jar"
151
+ )
152
+ self.dev.sync.push(
153
+ Path.joinpath(cur_dir, "assets/fastbot-thirdpart.jar"),
154
+ "/sdcard/fastbot-thirdpart.jar",
155
+ )
156
+ self.dev.sync.push(
157
+ Path.joinpath(cur_dir, "assets/kea2-thirdpart.jar"),
158
+ "/sdcard/kea2-thirdpart.jar",
159
+ )
160
+ self.dev.sync.push(
161
+ Path.joinpath(cur_dir, "assets/framework.jar"),
162
+ "/sdcard/framework.jar",
163
+ )
164
+ self.dev.sync.push(
165
+ Path.joinpath(cur_dir, "assets/fastbot_libs/arm64-v8a/libfastbot_native.so"),
166
+ "/data/local/tmp/arm64-v8a/libfastbot_native.so",
167
+ )
168
+ self.dev.sync.push(
169
+ Path.joinpath(cur_dir, "assets/fastbot_libs/armeabi-v7a/libfastbot_native.so"),
170
+ "/data/local/tmp/armeabi-v7a/libfastbot_native.so",
171
+ )
172
+ self.dev.sync.push(
173
+ Path.joinpath(cur_dir, "assets/fastbot_libs/x86/libfastbot_native.so"),
174
+ "/data/local/tmp/x86/libfastbot_native.so",
175
+ )
176
+ self.dev.sync.push(
177
+ Path.joinpath(cur_dir, "assets/fastbot_libs/x86_64/libfastbot_native.so"),
178
+ "/data/local/tmp/x86_64/libfastbot_native.so",
179
+ )
180
+
181
+ cwd = getProjectRoot()
182
+ whitelist = self.options.act_whitelist_file
183
+ blacklist = self.options.act_blacklist_file
184
+ if bool(whitelist) ^ bool(blacklist):
185
+ if whitelist:
186
+ file_to_push = cwd / 'configs' / 'awl.strings'
187
+ remote_path = whitelist
188
+ else:
189
+ file_to_push = cwd / 'configs' / 'abl.strings'
190
+ remote_path = blacklist
191
+
192
+ self.dev.sync.push(
193
+ file_to_push,
194
+ remote_path
195
+ )
196
+
197
+ def _startFastbotService(self) -> ADBStreamShell_V2:
198
+ shell_command = [
199
+ "CLASSPATH="
200
+ "/sdcard/monkeyq.jar:"
201
+ "/sdcard/framework.jar:"
202
+ "/sdcard/fastbot-thirdpart.jar:"
203
+ "/sdcard/kea2-thirdpart.jar",
204
+ "exec", "app_process",
205
+ "/system/bin", "com.android.commands.monkey.Monkey",
206
+ "--agent-u2" if self.options.agent == "u2" else "--agent",
207
+ "reuseq",
208
+ "--running-minutes", f"{self.options.running_mins}",
209
+ "--throttle", f"{self.options.throttle}",
210
+ "--bugreport",
211
+ "--output-directory", f"{self.options.device_output_root}/output_{self.options.log_stamp}",
212
+ ]
213
+
214
+ pkgs = itertools.chain.from_iterable(["-p", pkg] for pkg in self.options.packageNames)
215
+ shell_command.extend(pkgs)
216
+
217
+ if self.options.profile_period:
218
+ shell_command += ["--profile-period", f"{self.options.profile_period}"]
219
+
220
+ whitelist = self.options.act_whitelist_file
221
+ blacklist = self.options.act_blacklist_file
222
+ if bool(whitelist) ^ bool(blacklist):
223
+ if whitelist:
224
+ shell_command += ["--act-whitelist-file", f"{whitelist}"]
225
+ else:
226
+ shell_command += ["--act-blacklist-file", f"{blacklist}"]
227
+
228
+ shell_command += ["-v", "-v", "-v"]
229
+
230
+ if self.options.extra_args:
231
+ shell_command += self.options.extra_args
232
+
233
+ full_cmd = ["adb"] + (["-s", self.options.serial] if self.options.serial else []) + ["shell"] + shell_command
234
+
235
+
236
+ outfile = open(self.log_file, "w", encoding="utf-8", buffering=1)
237
+
238
+ logger.info("Options info: {}".format(asdict(self.options)))
239
+ logger.info("Launching fastbot with shell command:\n{}".format(" ".join(full_cmd)))
240
+ logger.info("Fastbot log will be saved to {}".format(outfile.name))
241
+
242
+ t = self.dev.stream_shell(shell_command, stdout=outfile, stderr=outfile)
243
+ return t
244
+
245
+ def close_on_exit(self, proc: ADBStreamShell_V2, f: IO):
246
+ self.return_code = proc.wait()
247
+ f.close()
248
+ if self.return_code != 0:
249
+ raise RuntimeError(f"Fastbot Error: Terminated with [code {self.return_code}] See {self.log_file} for details.")
250
+
251
+ def get_return_code(self):
252
+ if self.thread.is_running():
253
+ logger.info("Waiting for Fastbot to exit.")
254
+ return self.thread.wait()
255
+ return self.thread.poll() if self.android_release >= parse_version("7.0") else 0
256
+
257
+ def start(self):
258
+ # kill the fastbot process if runing.
259
+ self.dev.kill_proc("com.android.commands.monkey")
260
+ self.thread = self._activateFastbot()
261
+
262
+ def join(self):
263
+ self.thread.join()
264
+
265
+
266
+
267
+
@@ -0,0 +1,52 @@
1
+ import flatbuffers
2
+ from flatbuffers.compat import import_numpy
3
+ np = import_numpy()
4
+
5
+ class ActivityTimes(object):
6
+ __slots__ = ['_tab']
7
+
8
+ @classmethod
9
+ def GetRootAs(cls, buf, offset=0):
10
+ n = flatbuffers.encode.Get(flatbuffers.packer.uoffset, buf, offset)
11
+ x = ActivityTimes()
12
+ x.Init(buf, n + offset)
13
+ return x
14
+
15
+ @classmethod
16
+ def GetRootAsActivityTimes(cls, buf, offset=0):
17
+ """This method is deprecated. Please switch to GetRootAs."""
18
+ return cls.GetRootAs(buf, offset)
19
+ # ActivityTimes
20
+ def Init(self, buf, pos):
21
+ self._tab = flatbuffers.table.Table(buf, pos)
22
+
23
+ # ActivityTimes
24
+ def Activity(self):
25
+ o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(4))
26
+ if o != 0:
27
+ return self._tab.String(o + self._tab.Pos)
28
+ return None
29
+
30
+ # ActivityTimes
31
+ def Times(self):
32
+ o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(6))
33
+ if o != 0:
34
+ return self._tab.Get(flatbuffers.number_types.Int32Flags, o + self._tab.Pos)
35
+ return 0
36
+
37
+ def Start(builder): builder.StartObject(2)
38
+ def ActivityTimesStart(builder):
39
+ """This method is deprecated. Please switch to Start."""
40
+ return Start(builder)
41
+ def AddActivity(builder, activity): builder.PrependUOffsetTRelativeSlot(0, flatbuffers.number_types.UOffsetTFlags.py_type(activity), 0)
42
+ def ActivityTimesAddActivity(builder, activity):
43
+ """This method is deprecated. Please switch to AddActivity."""
44
+ return AddActivity(builder, activity)
45
+ def AddTimes(builder, times): builder.PrependInt32Slot(1, times, 0)
46
+ def ActivityTimesAddTimes(builder, times):
47
+ """This method is deprecated. Please switch to AddTimes."""
48
+ return AddTimes(builder, times)
49
+ def End(builder): return builder.EndObject()
50
+ def ActivityTimesEnd(builder):
51
+ """This method is deprecated. Please switch to End."""
52
+ return End(builder)
@@ -0,0 +1,74 @@
1
+ import flatbuffers
2
+ from flatbuffers.compat import import_numpy
3
+ np = import_numpy()
4
+
5
+ class ReuseEntry(object):
6
+ __slots__ = ['_tab']
7
+
8
+ @classmethod
9
+ def GetRootAs(cls, buf, offset=0):
10
+ n = flatbuffers.encode.Get(flatbuffers.packer.uoffset, buf, offset)
11
+ x = ReuseEntry()
12
+ x.Init(buf, n + offset)
13
+ return x
14
+
15
+ @classmethod
16
+ def GetRootAsReuseEntry(cls, buf, offset=0):
17
+ """This method is deprecated. Please switch to GetRootAs."""
18
+ return cls.GetRootAs(buf, offset)
19
+ # ReuseEntry
20
+ def Init(self, buf, pos):
21
+ self._tab = flatbuffers.table.Table(buf, pos)
22
+
23
+ # ReuseEntry
24
+ def Action(self):
25
+ o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(4))
26
+ if o != 0:
27
+ return self._tab.Get(flatbuffers.number_types.Uint64Flags, o + self._tab.Pos)
28
+ return 0
29
+
30
+ # ReuseEntry
31
+ def Targets(self, j):
32
+ o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(6))
33
+ if o != 0:
34
+ x = self._tab.Vector(o)
35
+ x += flatbuffers.number_types.UOffsetTFlags.py_type(j) * 4
36
+ x = self._tab.Indirect(x)
37
+ from .ActivityTimes import ActivityTimes
38
+ obj = ActivityTimes()
39
+ obj.Init(self._tab.Bytes, x)
40
+ return obj
41
+ return None
42
+
43
+ # ReuseEntry
44
+ def TargetsLength(self):
45
+ o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(6))
46
+ if o != 0:
47
+ return self._tab.VectorLen(o)
48
+ return 0
49
+
50
+ # ReuseEntry
51
+ def TargetsIsNone(self):
52
+ o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(6))
53
+ return o == 0
54
+
55
+ def Start(builder): builder.StartObject(2)
56
+ def ReuseEntryStart(builder):
57
+ """This method is deprecated. Please switch to Start."""
58
+ return Start(builder)
59
+ def AddAction(builder, action): builder.PrependUint64Slot(0, action, 0)
60
+ def ReuseEntryAddAction(builder, action):
61
+ """This method is deprecated. Please switch to AddAction."""
62
+ return AddAction(builder, action)
63
+ def AddTargets(builder, targets): builder.PrependUOffsetTRelativeSlot(1, flatbuffers.number_types.UOffsetTFlags.py_type(targets), 0)
64
+ def ReuseEntryAddTargets(builder, targets):
65
+ """This method is deprecated. Please switch to AddTargets."""
66
+ return AddTargets(builder, targets)
67
+ def StartTargetsVector(builder, numElems): return builder.StartVector(4, numElems, 4)
68
+ def ReuseEntryStartTargetsVector(builder, numElems):
69
+ """This method is deprecated. Please switch to Start."""
70
+ return StartTargetsVector(builder, numElems)
71
+ def End(builder): return builder.EndObject()
72
+ def ReuseEntryEnd(builder):
73
+ """This method is deprecated. Please switch to End."""
74
+ return End(builder)
@@ -0,0 +1,63 @@
1
+ import flatbuffers
2
+ from flatbuffers.compat import import_numpy
3
+ np = import_numpy()
4
+
5
+ class ReuseModel(object):
6
+ __slots__ = ['_tab']
7
+
8
+ @classmethod
9
+ def GetRootAs(cls, buf, offset=0):
10
+ n = flatbuffers.encode.Get(flatbuffers.packer.uoffset, buf, offset)
11
+ x = ReuseModel()
12
+ x.Init(buf, n + offset)
13
+ return x
14
+
15
+ @classmethod
16
+ def GetRootAsReuseModel(cls, buf, offset=0):
17
+ """This method is deprecated. Please switch to GetRootAs."""
18
+ return cls.GetRootAs(buf, offset)
19
+ # ReuseModel
20
+ def Init(self, buf, pos):
21
+ self._tab = flatbuffers.table.Table(buf, pos)
22
+
23
+ # ReuseModel
24
+ def Model(self, j):
25
+ o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(4))
26
+ if o != 0:
27
+ x = self._tab.Vector(o)
28
+ x += flatbuffers.number_types.UOffsetTFlags.py_type(j) * 4
29
+ x = self._tab.Indirect(x)
30
+ from .ReuseEntry import ReuseEntry
31
+ obj = ReuseEntry()
32
+ obj.Init(self._tab.Bytes, x)
33
+ return obj
34
+ return None
35
+
36
+ # ReuseModel
37
+ def ModelLength(self):
38
+ o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(4))
39
+ if o != 0:
40
+ return self._tab.VectorLen(o)
41
+ return 0
42
+
43
+ # ReuseModel
44
+ def ModelIsNone(self):
45
+ o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(4))
46
+ return o == 0
47
+
48
+ def Start(builder): builder.StartObject(1)
49
+ def ReuseModelStart(builder):
50
+ """This method is deprecated. Please switch to Start."""
51
+ return Start(builder)
52
+ def AddModel(builder, model): builder.PrependUOffsetTRelativeSlot(0, flatbuffers.number_types.UOffsetTFlags.py_type(model), 0)
53
+ def ReuseModelAddModel(builder, model):
54
+ """This method is deprecated. Please switch to AddModel."""
55
+ return AddModel(builder, model)
56
+ def StartModelVector(builder, numElems): return builder.StartVector(4, numElems, 4)
57
+ def ReuseModelStartModelVector(builder, numElems):
58
+ """This method is deprecated. Please switch to Start."""
59
+ return StartModelVector(builder, numElems)
60
+ def End(builder): return builder.EndObject()
61
+ def ReuseModelEnd(builder):
62
+ """This method is deprecated. Please switch to End."""
63
+ return End(builder)
@@ -0,0 +1,7 @@
1
+ from .ActivityTimes import ActivityTimes
2
+ from .ReuseEntry import ReuseEntry
3
+ from .ReuseModel import ReuseModel
4
+
5
+ __all__ = ['ActivityTimes', 'ReuseEntry', 'ReuseModel']
6
+
7
+