Skip to content

Commit 7129362

Browse files
committed
Add support to tools/ffdb.py to perform B2G 2.0 bulk data transfers for binary data uploads. Gives about 4MB/sec data uploads as opposed to ~350KB/sec on old B2G 1.4 devices.
1 parent 4fb1b15 commit 7129362

1 file changed

Lines changed: 36 additions & 21 deletions

File tree

tools/ffdb.py

Lines changed: 36 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -60,9 +60,10 @@ def logv(msg):
6060
# The messages are of form "bytelength:{jsondict}", where bytelength tells how many bytes
6161
# there are in the data that comes after the colon.
6262
# Returns a JSON dictionary of the received message.
63-
def read_b2g_response():
63+
def read_b2g_response(print_errors_to_console = True):
6464
global read_queue, b2g_socket
6565
read_queue += b2g_socket.recv(65536*2)
66+
payload = ''
6667
while ':' in read_queue:
6768
semicolon = read_queue.index(':')
6869
payload_len = int(read_queue[:semicolon])
@@ -74,12 +75,12 @@ def read_b2g_response():
7475
logv('Read a message of size ' + str(payload_len) + 'b from socket.')
7576
payload = json.loads(payload)
7677
# Log received errors immediately to console
77-
if 'error' in payload:
78+
if print_errors_to_console and 'error' in payload:
7879
print >> sys.stderr, 'Received error "' + payload['error'] + '"! Reason: ' + payload['message']
7980
return payload
8081

8182
# Sends a command to the B2G device and waits for the response and returns it as a JSON dict.
82-
def send_b2g_cmd(to, cmd, data = {}):
83+
def send_b2g_cmd(to, cmd, data = {}, print_errors_to_console = True):
8384
global b2g_socket
8485
msg = { 'to': to, 'type': cmd}
8586
msg = dict(msg.items() + data.items())
@@ -88,7 +89,7 @@ def send_b2g_cmd(to, cmd, data = {}):
8889
msg = str(len(msg))+':'+msg
8990
logv('Sending cmd:' + cmd + ' to:' + to)
9091
b2g_socket.sendall(msg)
91-
return read_b2g_response()
92+
return read_b2g_response(print_errors_to_console)
9293

9394
def escape_bytes(b):
9495
return str(b)
@@ -116,6 +117,13 @@ def send_b2g_data_chunk(to, data_blob):
116117
b2g_socket.sendall(message)
117118
return read_b2g_response()
118119

120+
def send_b2g_bulk_data(to, data_blob):
121+
message = 'bulk ' + to + ' stream ' + str(len(data_blob)) + ':'
122+
logv(message)
123+
b2g_socket.sendall(message)
124+
b2g_socket.sendall(data_blob)
125+
# It seems that B2G doesn't send any response JSON back after a bulk transfer is finished, so no read_b2g_response() here.
126+
119127
# Queries the device for a list of all installed apps.
120128
def b2g_get_appslist():
121129
global webappsActorName
@@ -253,28 +261,35 @@ def delete_temp_file():
253261

254262
print 'Uploading application package "' + target_app_path + '"...'
255263
print 'Size of compressed package: ' + sizeof_fmt(os.path.getsize(target_app_path)) + '.'
256-
uploadResponse = send_b2g_cmd(webappsActorName, 'uploadPackage')
257-
packageUploadActor = uploadResponse['actor']
258264
app_file = open(target_app_path, 'rb')
259265
data = app_file.read()
260266
file_size = len(data)
261-
chunk_size = 4*1024*1024
262-
i = 0
267+
268+
uploadResponse = send_b2g_cmd(webappsActorName, 'uploadPackage', { 'bulk': 'true'}, print_errors_to_console = False) # This may fail if on old device.
263269
start_time = time.time()
264-
while i < file_size:
265-
chunk = data[i:i+chunk_size]
266-
267-
send_b2g_data_chunk(packageUploadActor, chunk)
268-
i += chunk_size
269-
bytes_uploaded = min(i, file_size)
270-
cur_time = time.time()
271-
secs_elapsed = cur_time - start_time
272-
percentage_done = bytes_uploaded * 1.0 / file_size
273-
total_time = secs_elapsed / percentage_done
274-
time_left = total_time - secs_elapsed
275-
print sizeof_fmt(bytes_uploaded) + " uploaded, {:5.1f} % done.".format(percentage_done*100.0) + ' Elapsed: ' + str(int(secs_elapsed)) + ' seconds. Time left: ' + str(datetime.timedelta(seconds=int(time_left))) + '. Data rate: {:5.2f} KB/second.'.format(bytes_uploaded / 1024.0 / secs_elapsed)
276-
send_b2g_cmd(webappsActorName, 'install', { 'appId': str(uuid.uuid4()), 'upload': packageUploadActor })
270+
if 'actor' in uploadResponse and 'BulkActor' in uploadResponse['actor']: # New B2G 2.0 hotness: binary data transfer
271+
packageUploadActor = uploadResponse['actor']
272+
send_b2g_bulk_data(packageUploadActor, data)
273+
else: # Old B2G 1.4 and older, serialize binary data in JSON text strings (SLOW!)
274+
print 'Bulk upload is not supported, uploading binary data with old slow format. Consider flashing your device to FFOS 2.0 or newer to enjoy faster upload speeds.'
275+
uploadResponse = send_b2g_cmd(webappsActorName, 'uploadPackage')
276+
packageUploadActor = uploadResponse['actor']
277+
chunk_size = 4*1024*1024
278+
i = 0
279+
while i < file_size:
280+
chunk = data[i:i+chunk_size]
281+
282+
send_b2g_data_chunk(packageUploadActor, chunk)
283+
i += chunk_size
284+
bytes_uploaded = min(i, file_size)
285+
cur_time = time.time()
286+
secs_elapsed = cur_time - start_time
287+
percentage_done = bytes_uploaded * 1.0 / file_size
288+
total_time = secs_elapsed / percentage_done
289+
time_left = total_time - secs_elapsed
290+
print sizeof_fmt(bytes_uploaded) + " uploaded, {:5.1f} % done.".format(percentage_done*100.0) + ' Elapsed: ' + str(int(secs_elapsed)) + ' seconds. Time left: ' + str(datetime.timedelta(seconds=int(time_left))) + '. Data rate: {:5.2f} KB/second.'.format(bytes_uploaded / 1024.0 / secs_elapsed)
277291

292+
send_b2g_cmd(webappsActorName, 'install', { 'appId': str(uuid.uuid4()), 'upload': packageUploadActor })
278293
cur_time = time.time()
279294
secs_elapsed = cur_time - start_time
280295
print 'Upload of ' + sizeof_fmt(file_size) + ' finished. Total time elapsed: ' + str(int(secs_elapsed)) + ' seconds. Data rate: {:5.2f} KB/second.'.format(file_size / 1024.0 / secs_elapsed)

0 commit comments

Comments
 (0)