lamda 7.76__tar.gz → 7.85__tar.gz
Sign up to get free protection for your applications and to get access to all the features.
- {lamda-7.76 → lamda-7.85}/PKG-INFO +1 -1
- {lamda-7.76 → lamda-7.85}/lamda/__init__.py +1 -1
- {lamda-7.76 → lamda-7.85}/lamda/client.py +155 -4
- {lamda-7.76 → lamda-7.85}/lamda/rpc/application.proto +29 -0
- {lamda-7.76 → lamda-7.85}/lamda/rpc/services.proto +6 -0
- {lamda-7.76 → lamda-7.85}/lamda.egg-info/PKG-INFO +1 -1
- {lamda-7.76 → lamda-7.85}/README.md +0 -0
- {lamda-7.76 → lamda-7.85}/lamda/bcast.proto +0 -0
- {lamda-7.76 → lamda-7.85}/lamda/const.py +0 -0
- {lamda-7.76 → lamda-7.85}/lamda/exceptions.py +0 -0
- {lamda-7.76 → lamda-7.85}/lamda/google/protobuf/any.proto +0 -0
- {lamda-7.76 → lamda-7.85}/lamda/google/protobuf/api.proto +0 -0
- {lamda-7.76 → lamda-7.85}/lamda/google/protobuf/compiler/plugin.proto +0 -0
- {lamda-7.76 → lamda-7.85}/lamda/google/protobuf/descriptor.proto +0 -0
- {lamda-7.76 → lamda-7.85}/lamda/google/protobuf/duration.proto +0 -0
- {lamda-7.76 → lamda-7.85}/lamda/google/protobuf/empty.proto +0 -0
- {lamda-7.76 → lamda-7.85}/lamda/google/protobuf/field_mask.proto +0 -0
- {lamda-7.76 → lamda-7.85}/lamda/google/protobuf/source_context.proto +0 -0
- {lamda-7.76 → lamda-7.85}/lamda/google/protobuf/struct.proto +0 -0
- {lamda-7.76 → lamda-7.85}/lamda/google/protobuf/timestamp.proto +0 -0
- {lamda-7.76 → lamda-7.85}/lamda/google/protobuf/type.proto +0 -0
- {lamda-7.76 → lamda-7.85}/lamda/google/protobuf/wrappers.proto +0 -0
- {lamda-7.76 → lamda-7.85}/lamda/rpc/debug.proto +0 -0
- {lamda-7.76 → lamda-7.85}/lamda/rpc/file.proto +0 -0
- {lamda-7.76 → lamda-7.85}/lamda/rpc/policy.proto +0 -0
- {lamda-7.76 → lamda-7.85}/lamda/rpc/proxy.proto +0 -0
- {lamda-7.76 → lamda-7.85}/lamda/rpc/settings.proto +0 -0
- {lamda-7.76 → lamda-7.85}/lamda/rpc/shell.proto +0 -0
- {lamda-7.76 → lamda-7.85}/lamda/rpc/status.proto +0 -0
- {lamda-7.76 → lamda-7.85}/lamda/rpc/storage.proto +0 -0
- {lamda-7.76 → lamda-7.85}/lamda/rpc/types.proto +0 -0
- {lamda-7.76 → lamda-7.85}/lamda/rpc/uiautomator.proto +0 -0
- {lamda-7.76 → lamda-7.85}/lamda/rpc/util.proto +0 -0
- {lamda-7.76 → lamda-7.85}/lamda/rpc/wifi.proto +0 -0
- {lamda-7.76 → lamda-7.85}/lamda/types.py +0 -0
- {lamda-7.76 → lamda-7.85}/lamda.egg-info/SOURCES.txt +0 -0
- {lamda-7.76 → lamda-7.85}/lamda.egg-info/dependency_links.txt +0 -0
- {lamda-7.76 → lamda-7.85}/lamda.egg-info/not-zip-safe +0 -0
- {lamda-7.76 → lamda-7.85}/lamda.egg-info/requires.txt +0 -0
- {lamda-7.76 → lamda-7.85}/lamda.egg-info/top_level.txt +0 -0
- {lamda-7.76 → lamda-7.85}/setup.cfg +0 -0
- {lamda-7.76 → lamda-7.85}/setup.py +0 -0
@@ -57,6 +57,8 @@ logger.addHandler(handler)
|
|
57
57
|
|
58
58
|
sys.path.append(joinpath(dirname(__file__)))
|
59
59
|
sys.path.append(joinpath(dirname(__file__), "rpc"))
|
60
|
+
# use native resolver to support mDNS
|
61
|
+
os.environ["GRPC_DNS_RESOLVER"] = "native"
|
60
62
|
|
61
63
|
protos, services = grpc.protos_and_services("services.proto")
|
62
64
|
__all__ = [
|
@@ -179,6 +181,8 @@ def contain(a, b):
|
|
179
181
|
b.right <= a.right])
|
180
182
|
|
181
183
|
def equal(a, b):
|
184
|
+
if not isinstance(b, protos.Bound):
|
185
|
+
return False
|
182
186
|
return all([b.top == a.top,
|
183
187
|
b.left == a.left,
|
184
188
|
b.bottom == a.bottom,
|
@@ -194,6 +198,8 @@ Corner = protos.Corner
|
|
194
198
|
Direction = protos.Direction
|
195
199
|
GproxyType = protos.GproxyType
|
196
200
|
GrantType = protos.GrantType
|
201
|
+
ScriptRuntime = protos.ScriptRuntime
|
202
|
+
DataEncode = protos.DataEncode
|
197
203
|
|
198
204
|
Group = protos.Group
|
199
205
|
Key = protos.Key
|
@@ -256,6 +262,9 @@ TouchSequence.appendUp = touchSequenceAppendUp
|
|
256
262
|
TouchSequence.__getitem__ = touchSequenceIndexer
|
257
263
|
TouchSequence.__iter__ = touchSequenceIter
|
258
264
|
|
265
|
+
HookRpcRequest = protos.HookRpcRequest
|
266
|
+
HookRpcResponse = protos.HookRpcResponse
|
267
|
+
|
259
268
|
Bound.width = property(width)
|
260
269
|
Bound.height = property(height)
|
261
270
|
|
@@ -380,13 +389,14 @@ class GrpcRemoteExceptionInterceptor(ClientInterceptor):
|
|
380
389
|
|
381
390
|
|
382
391
|
class ObjectUiAutomatorOpStub:
|
383
|
-
def __init__(self,
|
392
|
+
def __init__(self, caller, selector):
|
384
393
|
"""
|
385
394
|
UiAutomator 子接口,用来模拟出实例的意味
|
386
395
|
"""
|
387
396
|
self._selector = selector
|
388
397
|
self.selector = Selector(**selector)
|
389
|
-
self.stub = stub
|
398
|
+
self.stub = caller.stub
|
399
|
+
self.caller = caller
|
390
400
|
def __str__(self):
|
391
401
|
selector = ", ".join(["{}={}".format(k, v) \
|
392
402
|
for k, v in self._selector.items()])
|
@@ -489,6 +499,72 @@ class ObjectUiAutomatorOpStub:
|
|
489
499
|
req = protos.SelectorOnlyRequest(selector=self.selector)
|
490
500
|
r = self.stub.selectorObjInfoOfAllInstances(req)
|
491
501
|
return r.objects
|
502
|
+
def all_instances(self):
|
503
|
+
"""
|
504
|
+
获取选择器选中的所有元素控件
|
505
|
+
"""
|
506
|
+
return list(self)
|
507
|
+
def _new_object(self, **kwargs):
|
508
|
+
selector = copy.deepcopy(self._selector)
|
509
|
+
selector.update(**kwargs)
|
510
|
+
instance = self.caller(**selector)
|
511
|
+
return instance
|
512
|
+
def text(self, txt):
|
513
|
+
return self._new_object(text=txt)
|
514
|
+
def resourceId(self, name):
|
515
|
+
return self._new_object(resourceId=name)
|
516
|
+
def description(self, desc):
|
517
|
+
return self._new_object(description=desc)
|
518
|
+
def packageName(self, name):
|
519
|
+
return self._new_object(packageName=name)
|
520
|
+
def className(self, name):
|
521
|
+
return self._new_object(className=name)
|
522
|
+
def textContains(self, needle):
|
523
|
+
return self._new_object(textContains=needle)
|
524
|
+
def descriptionContains(self, needle):
|
525
|
+
return self._new_object(descriptionContains=needle)
|
526
|
+
def textStartsWith(self, needle):
|
527
|
+
return self._new_object(textStartsWith=needle)
|
528
|
+
def descriptionStartsWith(self, needle):
|
529
|
+
return self._new_object(descriptionStartsWith=needle)
|
530
|
+
def textMatches(self, match):
|
531
|
+
return self._new_object(textMatches=match)
|
532
|
+
def descriptionMatches(self, match):
|
533
|
+
return self._new_object(descriptionMatches=match)
|
534
|
+
def resourceIdMatches(self, match):
|
535
|
+
return self._new_object(resourceIdMatches=match)
|
536
|
+
def packageNameMatches(self, match):
|
537
|
+
return self._new_object(packageNameMatches=match)
|
538
|
+
def classNameMatches(self, match):
|
539
|
+
return self._new_object(classNameMatches=match)
|
540
|
+
def checkable(self, value):
|
541
|
+
return self._new_object(checkable=value)
|
542
|
+
def clickable(self, value):
|
543
|
+
return self._new_object(clickable=value)
|
544
|
+
def focusable(self, value):
|
545
|
+
return self._new_object(focusable=value)
|
546
|
+
def scrollable(self, value):
|
547
|
+
return self._new_object(scrollable=value)
|
548
|
+
def longClickable(self, value):
|
549
|
+
return self._new_object(longClickable=value)
|
550
|
+
def enabled(self, value):
|
551
|
+
return self._new_object(enabled=value)
|
552
|
+
def checked(self, value):
|
553
|
+
return self._new_object(checked=value)
|
554
|
+
def focused(self, value):
|
555
|
+
return self._new_object(focused=value)
|
556
|
+
def selected(self, value):
|
557
|
+
return self._new_object(selected=value)
|
558
|
+
def index(self, idx):
|
559
|
+
return self._new_object(index=idx)
|
560
|
+
def instance(self, idx):
|
561
|
+
return self._new_object(instance=idx)
|
562
|
+
def __iter__(self):
|
563
|
+
"""
|
564
|
+
遍历所有符合选择器条件的元素实例
|
565
|
+
"""
|
566
|
+
yield from [self.instance(i) for i in \
|
567
|
+
range(self.count())]
|
492
568
|
def count(self):
|
493
569
|
"""
|
494
570
|
获取选择器选中控件的数量
|
@@ -957,7 +1033,25 @@ class UiAutomatorStub(BaseServiceStub):
|
|
957
1033
|
r = self.stub.waitForIdle(protos.Integer(value=timeout))
|
958
1034
|
return r.value
|
959
1035
|
def __call__(self, **kwargs):
|
960
|
-
return ObjectUiAutomatorOpStub(self
|
1036
|
+
return ObjectUiAutomatorOpStub(self, kwargs)
|
1037
|
+
|
1038
|
+
|
1039
|
+
class AppScriptRpcInterface(object):
|
1040
|
+
def __init__(self, stub, application,
|
1041
|
+
name):
|
1042
|
+
self.application = application
|
1043
|
+
self.stub = stub
|
1044
|
+
self.name = name
|
1045
|
+
def __call__(self, *args):
|
1046
|
+
call_args = dict()
|
1047
|
+
call_args["method"] = self.name
|
1048
|
+
call_args["args"] = args
|
1049
|
+
req = HookRpcRequest()
|
1050
|
+
req.package = self.application.applicationId
|
1051
|
+
req.callinfo = json.dumps(call_args)
|
1052
|
+
result = self.stub.callScript(req)
|
1053
|
+
r = json.loads(result.callresult)
|
1054
|
+
return r
|
961
1055
|
|
962
1056
|
|
963
1057
|
class ApplicationOpStub:
|
@@ -1114,6 +1208,51 @@ class ApplicationOpStub:
|
|
1114
1208
|
req.user = self.user
|
1115
1209
|
r = self.stub.isInstalled(req)
|
1116
1210
|
return r.value
|
1211
|
+
def attach_script(self, script, runtime=ScriptRuntime.RUNTIME_QJS,
|
1212
|
+
emit="",
|
1213
|
+
encode=DataEncode.DATA_ENCODE_NONE,
|
1214
|
+
standup=5):
|
1215
|
+
"""
|
1216
|
+
向应用注入持久化 Hook 脚本
|
1217
|
+
"""
|
1218
|
+
s = isinstance(script, str)
|
1219
|
+
script = script.encode() if s else script
|
1220
|
+
req = protos.HookRequest()
|
1221
|
+
req.package = self.applicationId
|
1222
|
+
req.script = script
|
1223
|
+
req.runtime = runtime
|
1224
|
+
req.standup = standup
|
1225
|
+
req.destination = emit
|
1226
|
+
req.encode = encode
|
1227
|
+
r = self.stub.attachScript(req)
|
1228
|
+
return r.value
|
1229
|
+
def detach_script(self):
|
1230
|
+
"""
|
1231
|
+
移除注入应用的 Hook 脚本
|
1232
|
+
"""
|
1233
|
+
req = protos.String(value=self.applicationId)
|
1234
|
+
r = self.stub.detachScript(req)
|
1235
|
+
return r.value
|
1236
|
+
def is_attached_script(self):
|
1237
|
+
"""
|
1238
|
+
检查使用在此应用注入了 Hook 脚本
|
1239
|
+
"""
|
1240
|
+
req = protos.String(value=self.applicationId)
|
1241
|
+
r = self.stub.isScriptAttached(req)
|
1242
|
+
return r.value
|
1243
|
+
def is_script_alive(self):
|
1244
|
+
"""
|
1245
|
+
检查应用中的 Hook 脚本是否正常
|
1246
|
+
"""
|
1247
|
+
req = protos.String(value=self.applicationId)
|
1248
|
+
r = self.stub.isScriptAlive(req)
|
1249
|
+
return r.value
|
1250
|
+
def __getattr__(self, name):
|
1251
|
+
"""
|
1252
|
+
调用注入应用 Hook 脚本的导出方法
|
1253
|
+
"""
|
1254
|
+
return AppScriptRpcInterface(self.stub, self,
|
1255
|
+
name)
|
1117
1256
|
|
1118
1257
|
|
1119
1258
|
class ApplicationStub(BaseServiceStub):
|
@@ -1974,6 +2113,14 @@ class Device(object):
|
|
1974
2113
|
session=None):
|
1975
2114
|
self.certificate = certificate
|
1976
2115
|
self.server = "{0}:{1}".format(host, port)
|
2116
|
+
policy = dict()
|
2117
|
+
policy["maxAttempts"] = 5
|
2118
|
+
policy["retryableStatusCodes"] = ["UNAVAILABLE"]
|
2119
|
+
policy["backoffMultiplier"] = 2
|
2120
|
+
policy["initialBackoff"] = "0.5s"
|
2121
|
+
policy["maxBackoff"] = "15s"
|
2122
|
+
config = json.dumps(dict(methodConfig=[{"name": [{}],
|
2123
|
+
"retryPolicy": policy,}]))
|
1977
2124
|
if certificate is not None:
|
1978
2125
|
with open(certificate, "rb") as fd:
|
1979
2126
|
key, crt, ca = self._parse_certdata(fd.read())
|
@@ -1983,10 +2130,14 @@ class Device(object):
|
|
1983
2130
|
self._chan = grpc.secure_channel(self.server, creds,
|
1984
2131
|
options=(("grpc.ssl_target_name_override",
|
1985
2132
|
self._parse_cname(crt)),
|
2133
|
+
("grpc.service_config", config),
|
1986
2134
|
("grpc.enable_http_proxy",
|
1987
2135
|
0)))
|
1988
2136
|
else:
|
1989
|
-
self._chan = grpc.insecure_channel(self.server
|
2137
|
+
self._chan = grpc.insecure_channel(self.server,
|
2138
|
+
options=(("grpc.service_config", config),
|
2139
|
+
("grpc.enable_http_proxy", 0))
|
2140
|
+
)
|
1990
2141
|
session = session or uuid.uuid4().hex
|
1991
2142
|
interceptors = [ClientSessionMetadataInterceptor(session),
|
1992
2143
|
GrpcRemoteExceptionInterceptor(),
|
@@ -13,6 +13,16 @@ enum GrantType {
|
|
13
13
|
GRANT_IGNORE = 2;
|
14
14
|
}
|
15
15
|
|
16
|
+
enum DataEncode {
|
17
|
+
DATA_ENCODE_NONE = 0;
|
18
|
+
DATA_ENCODE_ZLIB = 1;
|
19
|
+
}
|
20
|
+
|
21
|
+
enum ScriptRuntime {
|
22
|
+
RUNTIME_QJS = 0;
|
23
|
+
RUNTIME_V8 = 1;
|
24
|
+
}
|
25
|
+
|
16
26
|
message ApplicationRequest {
|
17
27
|
string name = 1;
|
18
28
|
string permission = 2;
|
@@ -83,3 +93,22 @@ message ApplicationProcesses {
|
|
83
93
|
message ApplicationPkgNames {
|
84
94
|
repeated string names = 1;
|
85
95
|
}
|
96
|
+
|
97
|
+
message HookRequest {
|
98
|
+
string package = 1;
|
99
|
+
bytes script = 2;
|
100
|
+
ScriptRuntime runtime = 3;
|
101
|
+
string destination = 4;
|
102
|
+
DataEncode encode = 5;
|
103
|
+
uint32 standup = 6;
|
104
|
+
}
|
105
|
+
|
106
|
+
message HookRpcRequest {
|
107
|
+
string package = 1;
|
108
|
+
string callinfo = 2;
|
109
|
+
}
|
110
|
+
|
111
|
+
message HookRpcResponse {
|
112
|
+
string package = 1;
|
113
|
+
string callresult = 2;
|
114
|
+
}
|
@@ -50,6 +50,12 @@ service Application {
|
|
50
50
|
rpc addToDozeModeWhiteList(ApplicationRequest) returns (Boolean) {}
|
51
51
|
rpc removeFromDozeModeWhiteList(ApplicationRequest) returns (Boolean) {}
|
52
52
|
rpc getIdentifierByLabel(String) returns (String) {}
|
53
|
+
|
54
|
+
rpc callScript(HookRpcRequest) returns (HookRpcResponse) {}
|
55
|
+
rpc isScriptAlive(String) returns (Boolean) {}
|
56
|
+
rpc isScriptAttached(String) returns (Boolean) {}
|
57
|
+
rpc attachScript(HookRequest) returns (Boolean) {}
|
58
|
+
rpc detachScript(String) returns (Boolean) {}
|
53
59
|
}
|
54
60
|
|
55
61
|
service Debug {
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|