-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathshashlik-run
executable file
·204 lines (168 loc) · 6.52 KB
/
shashlik-run
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
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
#!/usr/bin/env python3
import sys
import os
import subprocess
import argparse
from time import sleep
import socket
import threading
import socketserver
import http.server
from urllib import parse
PORT=60057
#Temporary prototype to launch the emulator and start the relevant app
#emulator is launched, and the icon is sent to the bootsplash
#starting the app is done by an ADB call into the running system, in a rather hacky way
#this will get replaced at some point, with shashlikd on the android side requesting things from here via TCP
#strategy depends on whether we re-use the emulator instance or start a new one
#Note. It is a proof of concept whislt we figure out what we want, I'm well aware that some parts are rubbish
#and there is are a few race conditions about startup
images_path = "/opt/shashlik/android"
lib_path = "/opt/shashlik/lib64"
shashlik_dir = os.path.expanduser("~/.local/share/shashlik") # FIXME use the XDG lib and put in constants.py
parser = argparse.ArgumentParser()
if not os.path.isdir(shashlik_dir + "sdcard.img"):
cmd = "/opt/shashlik/bin/mksdcard 500M %s/sdcard.img" % (shashlik_dir)
subprocess.call( cmd.strip().split(" ") )
#icon name is based on the package name in the install process
parser.add_argument("package_name", help="the name of the package to run")
#we take the user facing name as an argument as it saves us parsing the .apk twice
parser.add_argument("pretty_name", help="A user facing name of the app")
args = parser.parse_args()
httpd = 0
class ShashlikController(http.server.BaseHTTPRequestHandler):
def apk_file(s):
print("Sending APK")
apk_name = args.package_name
apk_path = shashlik_dir + "/" + apk_name + ".apk"
if os.path.exists(apk_path):
s.send_response(200)
s.send_header("Content-type", "application/vnd.android.package-archive")
s.end_headers()
with open(apk_path, "rb") as apk_file:
while True:
chunk = apk_file.read(1024)
if (not chunk):
break
s.wfile.write(chunk)
os.unlink(apk_path)
else:
s.send_response(403)
s.end_headers()
def startup(s):
apk_name = args.package_name
s.send_response(200)
s.send_header("Content-type", "text/plain")
s.end_headers()
s.wfile.write(apk_name.encode())
def do_GET(s):
url = parse.urlparse(s.path)
print (url)
if url.path == "/startup":
return s.startup()
if url.path == "/apk_file":
return s.apk_file()
s.send_response(404)
s.end_headers()
#starts the emulator instance.
#returns a subprocess.Popen instance
def start_emulator():
try:
os.mkdirs(shashlik_dir+"/system")
except:
pass
emulator_args = [
"/opt/shashlik/bin/emulator64-x86",
"-sysdir", "%s" % images_path,
"-system","%s/system.img" % images_path,
"-ramdisk", "%s/ramdisk.img" % images_path,
"-kernel", "%s/kernel-qemu" % images_path,
"-memory", "512",
"-data", "%s/userdata.img" % shashlik_dir,
"-datadir", "%s/system" % shashlik_dir,
"-sdcard", "%s/sdcard.img" % shashlik_dir,
"-noskin",
#"-skin 480x320",
"-gpu", "on",
"-selinux", "disabled",
"-qemu", "-append", "ro.product.cpu.abi2=armeabi-v7a"]
#print(emulator_args);
emulator_env = os.environ
emulator_env["LD_LIBRARY_PATH"] = lib_path + ":" + os.getenv("LD_LIBRARY_PATH","/lib")
emulator_env["PATH"] = "/opt/shashlik/bin" + ":" + os.getenv("PATH", "/usr/bin:/bin")
emulator_env["SHASHLIK_APPNAME"] = args.pretty_name
emulator_env["SHASHLIK_ICON"] = "%s/%s.png" % (shashlik_dir, args.package_name)
return subprocess.Popen(emulator_args, env=emulator_env)
#send an icon to the bootloader
def send_icon(icon_path):
socket_path = "/tmp/shashlik_controller"
if os.path.exists(socket_path):
os.remove(socket_path)
server = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
server.bind(socket_path)
server.listen(1)
connection, address = server.accept()
with open(icon_path, "rb") as icon:
while True:
chunk = icon.read(1024)
if (not chunk):
break
connection.send(chunk)
def start_controller():
global httpd
httpd = socketserver.TCPServer(("", PORT), ShashlikController, bind_and_activate=False)
httpd.allow_reuse_address=True
httpd.server_bind()
httpd.server_activate()
try:
httpd.serve_forever()
except KeyboardInterrupt:
pass
finally:
httpd.server_close()
#invoke ADB to install the apk if needed
#returns true on success, false if failed
def install_app(package_path):
try:
out = subprocess.check_output(args=["/opt/shashlik/bin/adb",
"-e",
"install",
package_path],
universal_newlines=True)
print (out)
rc = "Success" in out
if rc:
os.unlink(apk_path)
return rc
except:
return False
def launch_app(package_name):
try:
out = subprocess.check_output(args=["/opt/shashlik/bin/adb",
"-e",
"shell",
"monkey", "-p", package_name, "-c", "android.intent.category.LAUNCHER", "1"],
universal_newlines=True)
print (out)
return "injected" in out
except:
return False
apk_path = shashlik_dir + "/" + args.package_name + ".apk"
#if there's an emulator just re-use it
if subprocess.call(args=["pgrep", "emulator64-x86"]) == 0:
install_app(apk_path)
launch_app(args.package_name)
sys.exit(0)
print("starting emulator")
emulator_process = start_emulator()
#send the icon in a new thread way so we don't keep blocking if the emulator failed to start
icon_path = shashlik_dir + "/" + args.package_name + ".png"
icon_thread = threading.Thread(target=send_icon, args=(icon_path,))
icon_thread.daemon = True
icon_thread.start()
controller_thread = threading.Thread(target=start_controller)
controller_thread.start()
#block until the user closes the emulator
if emulator_process.returncode == None:
emulator_process.wait()
httpd.shutdown()