java android android-activity dexclassloader

java - Error de Android DexClassLoader, ''directorio de datos optimizado... no propiedad del usuario actual''



android-activity (1)

Estoy tratando de producir una aplicación de Android simple que puede cargar un archivo DEX desde la tarjeta SD en tiempo de ejecución.

La aplicación tiene dos actividades. La primera actividad es una pantalla simple que tiene un botón. Cuando se presiona el botón, se inicia la segunda actividad que hace que se invoque el método loadDex (). El método loadDex () intenta ubicar un archivo jar en la tarjeta SD y cargarlo en la aplicación actual.

Aquí está mi código para la primera actividad:

package poc.example.del.customclass; import android.content.Intent; import android.support.v7.app.ActionBarActivity; import android.os.Bundle; import android.view.Menu; import android.view.MenuItem; import android.view.View; public class MainActivity extends ActionBarActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); } @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.menu_main, menu); return true; } @Override public boolean onOptionsItemSelected(MenuItem item) { // Handle action bar item clicks here. The action bar will // automatically handle clicks on the Home/Up button, so long // as you specify a parent activity in AndroidManifest.xml. int id = item.getItemId(); //noinspection SimplifiableIfStatement if (id == R.id.action_settings) { return true; } return super.onOptionsItemSelected(item); } public void launchLoadClass(View view) { Intent intent = new Intent(MainActivity.this, LoadClass.class); startActivity(intent); } }

Aquí está el código para mi segunda actividad (la que carga el archivo DEX):

package poc.example.del.customclass; import android.support.v7.app.ActionBarActivity; import android.os.Bundle; import android.view.Menu; import android.view.MenuItem; import android.widget.TextView; import android.widget.Toast; import java.io.File; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import dalvik.system.DexClassLoader; public class LoadClass extends ActionBarActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_load_class); loadDex(); } @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.menu_load_class, menu); return true; } @Override public boolean onOptionsItemSelected(MenuItem item) { // Handle action bar item clicks here. The action bar will // automatically handle clicks on the Home/Up button, so long // as you specify a parent activity in AndroidManifest.xml. int id = item.getItemId(); //noinspection SimplifiableIfStatement if (id == R.id.action_settings) { return true; } return super.onOptionsItemSelected(item); } public void loadDex() { String dexFile = "/sdcard/output.jar"; File jarFile = new File(dexFile); if (jarFile.exists()) { // Toast.makeText(getApplicationContext(), "It Worked!", Toast.LENGTH_LONG).show(); DexClassLoader cl = new DexClassLoader (jarFile.toString (), "/data/test", null, ClassLoader.getSystemClassLoader()); } } }

El problema surge cuando se llama al constructor DexClassLoader. El siguiente error se puede encontrar en el registro:

03-25 10:15:48.441 1934-1934/poc.example.del.customclass E/AndroidRuntime﹕ FATAL EXCEPTION: main java.lang.RuntimeException: Unable to start activity ComponentInfo{poc.example.del.customclass/poc.example.del.customclass.LoadClass}: java.lang.IllegalArgumentException: Optimized data directory /data/test is not owned by the current user. Shared storage cannot protect your application from code injection attacks. at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2180) at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2230) at android.app.ActivityThread.access$600(ActivityThread.java:141) at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1234) at android.os.Handler.dispatchMessage(Handler.java:99) at android.os.Looper.loop(Looper.java:137) at android.app.ActivityThread.main(ActivityThread.java:5039) at java.lang.reflect.Method.invokeNative(Native Method) at java.lang.reflect.Method.invoke(Method.java:511) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:793) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:560) at dalvik.system.NativeStart.main(Native Method) Caused by: java.lang.IllegalArgumentException: Optimized data directory /data/test is not owned by the current user. Shared storage cannot protect your application from code injection attacks. at dalvik.system.DexFile.<init>(DexFile.java:100) at dalvik.system.DexFile.loadDex(DexFile.java:149) at dalvik.system.DexPathList.loadDexFile(DexPathList.java:261) at dalvik.system.DexPathList.makeDexElements(DexPathList.java:229) at dalvik.system.DexPathList.<init>(DexPathList.java:96) at dalvik.system.BaseDexClassLoader.<init>(BaseDexClassLoader.java:56) at dalvik.system.DexClassLoader.<init>(DexClassLoader.java:57) at poc.example.del.customclass.LoadClass.loadDex(LoadClass.java:54) at poc.example.del.customclass.LoadClass.onCreate(LoadClass.java:23) at android.app.Activity.performCreate(Activity.java:5104) at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1080) at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2144)             at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2230)             at android.app.ActivityThread.access$600(ActivityThread.java:141)             at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1234)             at android.os.Handler.dispatchMessage(Handler.java:99)             at android.os.Looper.loop(Looper.java:137)             at android.app.ActivityThread.main(ActivityThread.java:5039)             at java.lang.reflect.Method.invokeNative(Native Method)             at java.lang.reflect.Method.invoke(Method.java:511)             at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:793)             at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:560)             at dalvik.system.NativeStart.main(Native Method)

Aquí está la línea en el registro que creo que representa el problema:

java.lang.IllegalArgumentException: Optimized data directory /data/test is not owned by the current user. Shared storage cannot protect your application from code injection attacks.

Cualquier ayuda sería apreciada ya que he encontrado muy poca información en la web sobre el tema. Estoy desarrollando la aplicación para Android 4.2, Api 17.

Gracias por adelantado.


Encontré una respuesta después de unos días de seguir varios tutoriales. Pensé que la identificación publicaría la solución aquí en caso de que alguien más tenga un problema similar.

Por razones de seguridad, Android no permite que la aplicación cargue archivos en ninguna carpeta aleatoria. En su lugar, debe cargarse en el entorno de aplicaciones. Aquí está el código modificado que me permitió continuar con el proyecto. El código que se muestra es para el método ''loadDex ()'':

public void loadDex() { // Toast the show the method has been invoked correctly // Toast.makeText(getApplicationContext(), "loadDex() Method invoked", Toast.LENGTH_LONG).show(); // name of the DEX file String dexFile = "/output.jar"; // Get the path to the SD card File f = new File(Environment.getExternalStorageDirectory().toString() + dexFile); // optimized directory, the applciation and package directory final File optimizedDexOutputPath = getDir("outdex", 0); // DexClassLoader to get the file and write it to the optimised directory DexClassLoader classLoader = new DexClassLoader(f.getAbsolutePath(), optimizedDexOutputPath.getAbsolutePath(),null, getClassLoader()); // The classpath is created for the new class String completeClassName = "poc.example.del.mylibrary.name"; String methodToInvoke = "display"; try { Class<?> myClass = classLoader.loadClass(completeClassName); Object obj = (Object)myClass.newInstance(); Method m = myClass.getMethod(methodToInvoke); String s = ""+m.invoke(obj); makeToast(s); } catch (Exception e) { e.printStackTrace(); makeToast("Something went wrong!"); } }

La (s) línea (s) específica (s) de código que resolvió el problema es:

// DexClassLoader to get the file and write it to the optimized directory DexClassLoader classLoader = new DexClassLoader(f.getAbsolutePath(), optimizedDexOutputPath.getAbsolutePath(),null, getClassLoader());

Como puede ver, el método optimisedDexOutputPath, getAbsolutePath () devuelve el directorio que la aplicación puede usar para escribir archivos.

Espero que esto ayude a cualquier otra persona con un problema similar.