@@ -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
9394def 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.
120128def 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