Use file to pass arguments to the shell. Passing parameters directly through the intent have the following issues: - It limits the size of the parameters to 1024 bytes. - It is regularly broken by new versions of adb. R=ppi@chromium.org BUG=Fixes https://github.com/domokit/mojo/issues/488 Review URL: https://codereview.chromium.org/1414633004 .
diff --git a/mojo/devtools/common/devtoolslib/android_shell.py b/mojo/devtools/common/devtoolslib/android_shell.py index 611732e..ab03bb2 100644 --- a/mojo/devtools/common/devtoolslib/android_shell.py +++ b/mojo/devtools/common/devtoolslib/android_shell.py
@@ -15,6 +15,7 @@ import tempfile import threading import time +import uuid from devtoolslib.http_server import start_http_server from devtoolslib.shell import Shell @@ -349,8 +350,20 @@ parameters.extend(arguments) if parameters: - encodedParameters = json.dumps(parameters) - cmd += ['--es', 'encodedParameters', encodedParameters] + device_filename = ( + '/sdcard/%s/args_%s' % (_MOJO_SHELL_PACKAGE_NAME, str(uuid.uuid4()))) + with tempfile.NamedTemporaryFile(delete=False) as temp: + try: + for parameter in parameters: + temp.write(parameter) + temp.write('\n') + temp.close() + subprocess.check_call(self._adb_command( + ['push', temp.name, device_filename])) + finally: + os.remove(temp.name) + + cmd += ['--es', 'argsFile', device_filename] subprocess.check_call(cmd, stdout=self.verbose_pipe)
diff --git a/shell/android/apk/AndroidManifest.xml.jinja2 b/shell/android/apk/AndroidManifest.xml.jinja2 index 0229050..9408fd4 100644 --- a/shell/android/apk/AndroidManifest.xml.jinja2 +++ b/shell/android/apk/AndroidManifest.xml.jinja2
@@ -12,14 +12,15 @@ android:versionName="{{ version_name }}"> <uses-sdk android:minSdkVersion="14" android:targetSdkVersion="23" /> - <uses-permission android:name="android.permission.INTERNET"/> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/> <uses-permission android:name="android.permission.ACCESS_NETWORK_CONDITIONS"/> + <uses-permission android:name="android.permission.CAMERA" /> + <uses-permission android:name="android.permission.INTERNET"/> + <uses-permission android:name="android.permission.NFC"/> <uses-permission android:name="android.permission.READ_CONTACTS" /> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/> - <uses-permission android:name="android.permission.NFC"/> <uses-permission android:name="android.permission.RECORD_AUDIO"/> - <uses-permission android:name="android.permission.CAMERA" /> + <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> <application android:icon="@mipmap/ic_launcher" android:name="org.chromium.mojo.shell.MojoShellApplication"
diff --git a/shell/android/apk/src/org/chromium/mojo/shell/ShellService.java b/shell/android/apk/src/org/chromium/mojo/shell/ShellService.java index efb129c..c6f758c 100644 --- a/shell/android/apk/src/org/chromium/mojo/shell/ShellService.java +++ b/shell/android/apk/src/org/chromium/mojo/shell/ShellService.java
@@ -14,7 +14,6 @@ import android.net.Uri; import android.os.Binder; import android.os.IBinder; -import android.util.JsonReader; import android.util.Log; import org.chromium.base.ApplicationStatus; @@ -28,9 +27,10 @@ import org.chromium.mojom.mojo.ServiceProvider; import org.chromium.mojom.mojo.Shell; +import java.io.BufferedReader; import java.io.File; +import java.io.FileReader; import java.io.IOException; -import java.io.StringReader; import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.Arrays; @@ -168,9 +168,9 @@ public int onStartCommand(Intent intent, int flags, int startId) { // A client is starting this service; make sure the shell is initialized. // Note that ensureInitialized is gated by the mInitialized boolean flag. This means that - // only the first set of parameters will ever be taken into account. + // only the first set of arguments will ever be taken into account. // TODO(eseidel): ShellService can fail, but we're ignoring the return. - ensureStarted(getApplicationContext(), getParametersFromIntent(intent)); + ensureStarted(getApplicationContext(), getArgsFromIntent(intent)); if (intent.hasExtra(APPLICATION_URL_EXTRA)) { // This intent requests we start an application. String urlExtra = intent.getStringExtra(APPLICATION_URL_EXTRA); @@ -200,7 +200,7 @@ /** * Initializes the native system and starts the shell. **/ - private void ensureStarted(Context applicationContext, String[] parameters) { + private void ensureStarted(Context applicationContext, String[] args) { if (mInitialized) return; try { FileHelper.extractFromAssets(applicationContext, NETWORK_LIBRARY_APP, @@ -212,22 +212,21 @@ // The shell child executable needs to be ... executable. mojoShellChild.setExecutable(true, true); - List<String> parametersList = new ArrayList<String>(); + List<String> argsList = new ArrayList<String>(); - parametersList.add("--args-for=mojo:notifications " + R.mipmap.ic_launcher); + argsList.add("--args-for=mojo:notifications " + R.mipmap.ic_launcher); // Program name. - if (parameters != null) { - parametersList.addAll(Arrays.asList(parameters)); + if (args != null) { + argsList.addAll(Arrays.asList(args)); } else { - // Apply default parameters. - parametersList.add("--origin=" + DEFAULT_ORIGIN); - parametersList.add("--url-mappings=mojo:window_manager=" + DEFAULT_WM); + // Apply default arguments. + argsList.add("--origin=" + DEFAULT_ORIGIN); + argsList.add("--url-mappings=mojo:window_manager=" + DEFAULT_WM); } nativeStart(applicationContext, applicationContext.getAssets(), - mojoShellChild.getAbsolutePath(), - parametersList.toArray(new String[parametersList.size()]), + mojoShellChild.getAbsolutePath(), argsList.toArray(new String[argsList.size()]), getLocalAppsDir(applicationContext).getAbsolutePath(), getTmpDir(applicationContext).getAbsolutePath(), getHomeDir(applicationContext).getAbsolutePath()); @@ -238,28 +237,31 @@ } } - private static String[] getParametersFromIntent(Intent intent) { + private static String[] getArgsFromIntent(Intent intent) { if (intent == null) { return null; } - String[] parameters = intent.getStringArrayExtra("parameters"); - if (parameters != null) { - return parameters; - } - String encodedParameters = intent.getStringExtra("encodedParameters"); - if (encodedParameters != null) { - JsonReader reader = new JsonReader(new StringReader(encodedParameters)); - List<String> parametersList = new ArrayList<String>(); + String argsFile = intent.getStringExtra("argsFile"); + if (argsFile != null) { + File file = new File(argsFile); + if (!file.isFile()) { + return null; + } try { - reader.beginArray(); - while (reader.hasNext()) { - parametersList.add(reader.nextString()); + List<String> argsList = new ArrayList<String>(); + try (BufferedReader bufferedReader = new BufferedReader(new FileReader(file))) { + String line; + while ((line = bufferedReader.readLine()) != null) { + argsList.add(line); + } + return argsList.toArray(new String[argsList.size()]); + } catch (IOException e) { + Log.w(TAG, e.getMessage(), e); } - reader.endArray(); - reader.close(); - return parametersList.toArray(new String[parametersList.size()]); - } catch (IOException e) { - Log.w(TAG, e.getMessage(), e); + } finally { + if (!file.delete()) { + Log.w(TAG, "Unable to delete args file."); + } } } return null; @@ -320,8 +322,8 @@ * Initializes the native system. This API should be called only once per process. **/ private static native void nativeStart(Context context, AssetManager assetManager, - String mojoShellChildPath, String[] parameters, String bundledAppsDirectory, - String tmpDir, String homeDir); + String mojoShellChildPath, String[] args, String bundledAppsDirectory, String tmpDir, + String homeDir); private static native void nativeAddApplicationURL(String url);