Skip to content

Commit

Permalink
add another process
Browse files Browse the repository at this point in the history
  • Loading branch information
Catherine22 committed Feb 15, 2017
1 parent dc7b3a0 commit 2e42849
Show file tree
Hide file tree
Showing 5 changed files with 292 additions and 9 deletions.
7 changes: 6 additions & 1 deletion app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,12 @@
</activity>

<activity android:name="com.catherine.resource1.MainActivity" />
<activity android:name="com.catherine.resource2.MainActivity" />
<activity
android:name="com.catherine.resource2.MainActivity"
android:process=":resource2" />
<activity
android:name=".OpenResourceActivity"
android:process=":resource2" />
</application>

</manifest>
11 changes: 8 additions & 3 deletions app/src/main/java/com/catherine/classloader/MainActivity.java
Original file line number Diff line number Diff line change
Expand Up @@ -65,12 +65,17 @@ private void printHowClassLoaderWorks() {
public void onClick(View v) {
switch (v.getId()) {
case R.id.bt_load_apk1:
((MyApplication) getApplication()).RemoveApk();
// ((MyApplication) getApplication()).RemoveApk();
openApk(MyConfig.apk1);
break;
case R.id.bt_load_apk2:
((MyApplication) getApplication()).RemoveApk();
openApk(MyConfig.apk2);
// ((MyApplication) getApplication()).RemoveApk();
// openApk(MyConfig.apk2);


Intent intent2 = new Intent();
intent2.setClass(MainActivity.this, OpenResourceActivity.class);
startActivity(intent2);
break;
case R.id.bt_call_method:
try {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.catherine.classloader;

import android.content.Context;
import android.content.res.Resources;
import android.util.Log;

import java.net.URL;
Expand All @@ -23,10 +24,9 @@ public class MyDexClassLoader extends DexClassLoader {
private static final String TAG = "MyDexClassLoader";

/**
*
* @param application MyApplication
* @param dexPath String: the list of jar/apk files containing classes and resources, delimited by File.pathSeparator, which defaults to ":" on Android
* @param soPath native libraries (path of .so files)
* @param dexPath String: the list of jar/apk files containing classes and resources, delimited by File.pathSeparator, which defaults to ":" on Android
* @param soPath native libraries (path of .so files)
* @param classloader the parent class loader
*/
public MyDexClassLoader(MyApplication application, String dexPath, String soPath, ClassLoader classloader) {
Expand Down Expand Up @@ -72,13 +72,13 @@ protected synchronized Package getPackage(String name) {
}

@Override
public Class<?> loadClass(String name) throws ClassNotFoundException {
public Class<?> loadClass(String name) throws ClassNotFoundException{
Log.d(TAG, "loadClass:" + name);
return super.loadClass(name);
}

@Override
protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException{
Log.d(TAG, "loadClass:" + name + " : " + resolve);
return super.loadClass(name, resolve);
}
Expand Down
217 changes: 217 additions & 0 deletions app/src/main/java/com/catherine/classloader/OpenResourceActivity.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,217 @@
package com.catherine.classloader;

import android.app.Activity;
import android.content.Intent;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.os.Process;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;

import java.io.File;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

/**
* Created by Catherine on 2017/2/15.
* Soft-World Inc.
* catherine919@soft-world.com.tw
*/

public class OpenResourceActivity extends Activity implements View.OnClickListener {
private final static String TAG = "OpenResourceActivity";
private TextView tv_console;
private Button bt_call_method, bt_launch_apk;

private Class<?> apkActivity;
private Class<?> apkUtils;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_open_resource2);
tv_console = (TextView) findViewById(R.id.tv_console);
bt_call_method = (Button) findViewById(R.id.bt_call_method);
bt_call_method.setOnClickListener(this);
bt_launch_apk = (Button) findViewById(R.id.bt_launch_apk);
bt_launch_apk.setOnClickListener(this);

openApk(MyConfig.apk2);
}

@Override
protected void onDestroy() {
//Remove the latest loaded-apk
((MyApplication) getApplication()).RemoveApk();
Log.d(TAG, "onDestroy");
Process.killProcess(Process.myPid());
super.onDestroy();
}

public void openApk(String fileName) {
String history = tv_console.getText().toString();
tv_console.setText("Loading..." + "\n----\n" + history);

logClassLoader("start to load apk");
((MyApplication) getApplication()).LoadApk(fileName);
logClassLoader("apk loaded");

//switch apks
try {
if (MyConfig.apk1.equals(fileName)) {
apkActivity = getClassLoader().loadClass(MyConfig.APK1_ACTIVITY_MAIN);
apkUtils = getClassLoader().loadClass(MyConfig.APK1_UTILS);

Log.d(TAG, "Load the class of the apk by " + apkActivity.getClassLoader());

} else if (MyConfig.apk2.equals(fileName)) {
apkActivity = getClassLoader().loadClass(MyConfig.APK2_ACTIVITY_MAIN);
apkUtils = getClassLoader().loadClass(MyConfig.APK2_UTILS);
}
history = tv_console.getText().toString();
tv_console.setText(getApkInfo(fileName) + "\n----\n" + "Done!" + "\n----\n" + history);
} catch (Exception e) {
e.printStackTrace();

if (e instanceof ClassNotFoundException) {
history = tv_console.getText().toString();
tv_console.setText("Have you ever put your apk into correct directory?" + "\n----\n" + history);
}
}
}

private void logClassLoader(String msg) {
ClassLoader oldloader = getClass().getClassLoader();
int sum = 0;
try {
while (oldloader != null) {
Log.e(msg + sum, "" + oldloader);
sum++;
oldloader = oldloader.getParent();
}
Log.e(msg + sum, "" + oldloader);
} catch (Exception e) {
e.printStackTrace();
}
}

public String getApkInfo(String fileName) {
try {
String dexPath = null;
if (getExternalFilesDir(null) != null) {
dexPath = new File(getExternalFilesDir(null), fileName).getAbsolutePath();
} else if (getFilesDir() != null) {
dexPath = new File(getFilesDir(), fileName).getAbsolutePath();
}

PackageManager pm = getPackageManager();
PackageInfo info = pm.getPackageArchiveInfo(dexPath, 0);

StringBuilder sb = new StringBuilder();
sb.append("\n*** Apk info ***\n");
sb.append("versionCode:" + info.versionCode);
sb.append("\nversionName:" + info.versionName);
sb.append("\n*** Apk info ***\n");

return sb.toString();
} catch (Exception e) {
e.printStackTrace();
return e.toString();
}
}

@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.bt_call_method:
try {
//set null as the first parameter of invoke() while invoking a static method.
//static String getInputStringStatic(String value)
Method getInputStringStatic = apkUtils.getDeclaredMethod("getInputStringStatic", String.class);
String returns1 = (String) getInputStringStatic.invoke(null, "Hello, I'm your classLoader");
String history = tv_console.getText().toString();
tv_console.setText("getInputStringStatic:\t" + returns1 + "\n----\n" + history);

//static int getInputIntStatic(Integer value)
Method getInputIntStatic = apkUtils.getDeclaredMethod("getInputIntStatic", Integer.class);
int returns2 = (Integer) getInputIntStatic.invoke(null, 86400);
history = tv_console.getText().toString();
tv_console.setText("getInputIntStatic:\t" + returns2 + "\n----\n" + history);

//static String getStringValueStatic()
Method getStringValueStatic = apkUtils.getDeclaredMethod("getStringValueStatic");
String returns3 = (String) getStringValueStatic.invoke(null);
history = tv_console.getText().toString();
tv_console.setText("getStringValueStatic:\t" + returns3 + "\n----\n" + history);

//static int getIntValueStatic()
Method getIntValueStatic = apkUtils.getDeclaredMethod("getIntValueStatic");
int returns4 = (Integer) getIntValueStatic.invoke(null);
history = tv_console.getText().toString();
tv_console.setText("getIntValueStatic:\t" + returns4 + "\n----\n" + history);


//Get constructor for not-static method
Constructor<?> cons = apkUtils.getConstructor();

//String getStringValue()
Method getStringValue = apkUtils.getDeclaredMethod("getStringValue");
String returns5 = (String) getStringValue.invoke(cons.newInstance());
history = tv_console.getText().toString();
tv_console.setText("getStringValue:\t" + returns5 + "\n----\n" + history);

//int getIntValue()
Method getIntValue = apkUtils.getDeclaredMethod("getIntValue");
int returns6 = (Integer) getIntValue.invoke(cons.newInstance());
history = tv_console.getText().toString();
tv_console.setText("getIntValue:\t" + returns6 + "\n----\n" + history);

//Fields
Field myStaticField = apkUtils.getDeclaredField("myStaticField");

history = tv_console.getText().toString();
tv_console.setText(myStaticField.getName() + ":\t" + myStaticField.get(null) + "\n----\n" + history);

myStaticField.setAccessible(true);//You can update the field.
myStaticField.set(null, "new value");
myStaticField.setAccessible(false);

history = tv_console.getText().toString();
tv_console.setText(myStaticField.getName() + " updated:\t" + myStaticField.get(null) + "\n----\n" + history);
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (NullPointerException e) {
e.printStackTrace();

String history = tv_console.getText().toString();
tv_console.setText("Please load any apk first." + "\n----\n" + history);
} catch (NoSuchFieldException e) {
e.printStackTrace();
}
break;
case R.id.bt_launch_apk:
try {
Intent intent = new Intent();
intent.setClass(OpenResourceActivity.this, apkActivity);
startActivity(intent);
} catch (NullPointerException e) {
e.printStackTrace();

String history = tv_console.getText().toString();
tv_console.setText("Please load any apk first." + "\n----\n" + history);
}
break;
}
}
}
56 changes: 56 additions & 0 deletions app/src/main/res/layout/activity_open_resource2.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@android:color/white"
android:orientation="vertical">

<ScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_above="@+id/bt_call_method">

<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">

<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="console:"
android:textColor="#414141"
android:textSize="14sp" />

<TextView
android:id="@+id/tv_console"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:textColor="#414141"
android:textSize="14sp" />

</LinearLayout>
</ScrollView>

<Button
android:id="@+id/bt_call_method"
android:layout_width="match_parent"
android:layout_height="40dp"
android:layout_above="@+id/bt_launch_apk"
android:layout_marginTop="1dp"
android:background="#414141"
android:text="CALL METHOD"
android:textColor="@android:color/white"
android:textSize="16sp" />

<Button
android:id="@+id/bt_launch_apk"
android:layout_width="match_parent"
android:layout_height="40dp"
android:layout_alignParentBottom="true"
android:layout_marginTop="1dp"
android:background="#414141"
android:text="LAUNCH ACTIVITY"
android:textColor="@android:color/white"
android:textSize="16sp" />
</RelativeLayout>

0 comments on commit 2e42849

Please sign in to comment.