一、概念
进程与线程:
线程是CPU调度的最小单元,同时线程是一种有限的系统资源;进程一般指一个执行单元,在PC和移动设备上指一个程序或者一个应用。一个进程可以包含多个线程,因此进程和线程是包含与被包含的关系。
IPC(进程间通信),是指两个进程之间进行数据交换的过程。
二、为什么使用多进程
- 在Android中,虚拟机分配给各个进程的运行内存是有限制值的(这个值可以是32M,48M,64M等,根据机型而定),多进程App可以在系统中申请多份内存,对于一些占用内存过多的模块,可以使用独立的进程。
- 为了确保某些任务的执行和完成,不受当前进程退出的影响,也可以使用独立的进程。
- 多进程之间可以相互保活。
三、多进程启动方式
在Android中,一个应用开启多个进程只有一种方法,就是给四大组件(Activity、Service、Receiver、ContentProvider)在AndroidManifest中指定android:process属性。
//AndroidManifest.xml
<activity android:name=".ActivityX"
android:process=":ActivityX" //运行后,系统会创建一个单独进程,进程名为"com.tomorrow.androidtest8:ActivityX"
android:launchMode="standard">
<intent-filter>
<action android:name="com.tomorrow.androidtest8.action.x"/>
</intent-filter>
</activity>
<activity android:name=".ActivityY"
android:process="com.tomorrow.androidtest8.ActivityY" //运行后,系统会创建一个单独进程,进程名为"com.tomorrow.androidtest8.ActivityY"
android:launchMode="standard">
<intent-filter>
<action android:name="com.tomorrow.androidtest8.action.y"/>
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
运行命令:
adb shell "ps|grep com.tomorrow.androidtest8"
得到三个进程信息:
u0_a190 23067 528 735988 53096 SyS_epoll_ b6ce9c64 S com.tomorrow.androidtest8
u0_a190 23324 528 736552 55824 SyS_epoll_ b6ce9c64 S com.tomorrow.androidtest8:ActivityX
u0_a190 23385 528 749376 55604 SyS_epoll_ b6ce9c64 S com.tomorrow.androidtest8.ActivityY
":ActivityX"与"com.tomorrow.androidtest8.ActivityY"两种方式的区别:
(1)":ActivityX"表示当前完整的进程名为:当前应用包名加上":ActivityX";而"com.tomorrow.androidtest8.ActivityY"表示当前完整的进程名。
(2)以":"开头的进程属于当前应用的私有进程,而不以":"开头的进程属于全局进程。
四、sharedUserId
同一个应用间的多进程,相当于两个不同的应用采用了sharedUserId的模式,签名相同且sharedUserId相同。
进程名 PID UID 内存信息
public class MainActivity extends Activity {
private static final String TAG = "MainActivity";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Log.d(TAG, "zwm, onCreate");
getProcessName();
getPidAndUid();
getMemoryInfo();
}
private void getProcessName() {
String processName = null;
try {
File file = new File("/proc/" + android.os.Process.myPid() + "/" + "cmdline");
BufferedReader mBufferedReader = new BufferedReader(new FileReader(file));
processName = mBufferedReader.readLine().trim();
mBufferedReader.close();
} catch (Exception e) {
e.printStackTrace();
}
Log.d(TAG, "zwm, processName: " + processName);
}
private void getPidAndUid() {
int pid = android.os.Process.myPid();
int uid = android.os.Process.myUid();
Log.d(TAG, "zwm, pid: " + pid + ", uid: " + uid);
}
private void getMemoryInfo(){
Runtime rt = Runtime.getRuntime();
long maxMemory = rt.maxMemory();
Log.d(TAG, "zwm, maxMemory:" + Long.toString(maxMemory/(1024*1024)));
ActivityManager activityManager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
Log.d(TAG, "zwm, getMemoryClass:" + Long.toString(activityManager.getMemoryClass()));
Log.d(TAG, "zwm, getLargeMemoryClass:" + Long.toString(activityManager.getLargeMemoryClass())); //largeHeap属性设置为true时对应的最大内存
}
}
2019-11-01 13:25:18.661 10756-10756/com.tomorrow.hotfixdemo D/MainActivity: zwm, onCreate
2019-11-01 13:25:18.663 10756-10756/com.tomorrow.hotfixdemo D/MainActivity: zwm, processName: com.tomorrow.hotfixdemo
2019-11-01 13:25:18.663 10756-10756/com.tomorrow.hotfixdemo D/MainActivity: zwm, pid: 10756, uid: 10179
2019-11-01 13:25:18.663 10756-10756/com.tomorrow.hotfixdemo D/MainActivity: zwm, maxMemory:256
2019-11-01 13:25:18.664 10756-10756/com.tomorrow.hotfixdemo D/MainActivity: zwm, getMemoryClass:256
2019-11-01 13:25:18.664 10756-10756/com.tomorrow.hotfixdemo D/MainActivity: zwm, getLargeMemoryClass:512
PID:
PID是进程的身份标识,程序运行时系统会自动分配给进程一个独一无二的PID。
UID:
UID在应用安装到设备中时被分配,并在这个设备中保持它的永久性。
UID配置:
- 不同APP如果签名不同,不能配置相同的android:sharedUserId属性
例如:
APP1使用签名1,并且配置了android:sharedUserId="com.tomorrow.uid.test",使用AS在设备上成功安装。
APP2使用签名2,并且配置了android:sharedUserId="com.tomorrow.uid.test",使用AS在设备上不能成功安装,报以下错误:
Installation failed with message Failed to finalize session : INSTALL_FAILED_SHARED_USER_INCOMPATIBLE:
Package couldn't be installed in /data/app/com.tomorrow.testnetworkcache-SmlOnzNuV8-JcRbzfG6SGQ==:
Package com.tomorrow.testnetworkcache has no signatures that match those in shared user com.tomorrow.uid.test; ignoring!.
- 不同APP如果签名相同,能配置相同的android:sharedUserId属性
例如:
APP1使用签名1,并且配置了android:sharedUserId="com.tomorrow.uid.test",使用AS在设备上成功安装。
APP2使用签名1,并且配置了android:sharedUserId="com.tomorrow.uid.test",使用AS在设备上成功安装。
APP1跟APP2具有相同的UID。
UID作用:
- 不同APP的数据目录共享(/data/data/app包名/)
情况1:不同APP使用相同的签名,并且配置了相同的android:sharedUserId属性,共享成功。
APP1使用签名1,并且配置了android:sharedUserId="com.tomorrow.uid.test",
MainActivity代码如下:
public class MainActivity extends Activity {
private static final String TAG = "MainActivity";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Log.d(TAG, "zwm, onCreate");
getProcessName();
getPidAndUid();
getMemoryInfo();
writeSettings(this, "Hot Fix Settings!");
}
private void getProcessName() {
String processName = null;
try {
File file = new File("/proc/" + android.os.Process.myPid() + "/" + "cmdline");
BufferedReader mBufferedReader = new BufferedReader(new FileReader(file));
processName = mBufferedReader.readLine().trim();
mBufferedReader.close();
} catch (Exception e) {
e.printStackTrace();
}
Log.d(TAG, "zwm, processName: " + processName);
}
private void getPidAndUid() {
int pid = android.os.Process.myPid();
int uid = android.os.Process.myUid();
Log.d(TAG, "zwm, pid: " + pid + ", uid: " + uid);
}
private void getMemoryInfo(){
Runtime rt = Runtime.getRuntime();
long maxMemory = rt.maxMemory();
Log.d(TAG, "zwm, maxMemory:" + Long.toString(maxMemory/(1024*1024)));
ActivityManager activityManager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
Log.d(TAG, "zwm, getMemoryClass:" + Long.toString(activityManager.getMemoryClass()));
Log.d(TAG, "zwm, getLargeMemoryClass:" + Long.toString(activityManager.getLargeMemoryClass()));
}
public void writeSettings(Context context, String data) {
Log.d(TAG, "zwm, writeSettings: " + data);
FileOutputStream fOut = null;
OutputStreamWriter osw = null;
try {
//默认建立在data/data/app包名/file/
fOut = context.openFileOutput("settings.dat", MODE_PRIVATE);
osw = new OutputStreamWriter(fOut);
osw.write(data);
osw.flush();
Log.d(TAG, "zwm, writeSettings success");
} catch (Exception e) {
e.printStackTrace();
Log.d(TAG, "zwm, writeSettings fail");
} finally {
if(osw != null) {
try {
osw.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(fOut != null) {
try {
fOut.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
运行输出log如下:
2019-11-01 15:38:55.676 12441-12441/com.tomorrow.hotfixdemo D/MainActivity: zwm, onCreate
2019-11-01 15:38:55.678 12441-12441/com.tomorrow.hotfixdemo D/MainActivity: zwm, processName: com.tomorrow.hotfixdemo
2019-11-01 15:38:55.678 12441-12441/com.tomorrow.hotfixdemo D/MainActivity: zwm, pid: 12441, uid: 10399
2019-11-01 15:38:55.679 12441-12441/com.tomorrow.hotfixdemo D/MainActivity: zwm, maxMemory:256
2019-11-01 15:38:55.679 12441-12441/com.tomorrow.hotfixdemo D/MainActivity: zwm, getMemoryClass:256
2019-11-01 15:38:55.679 12441-12441/com.tomorrow.hotfixdemo D/MainActivity: zwm, getLargeMemoryClass:512
2019-11-01 15:38:55.679 12441-12441/com.tomorrow.hotfixdemo D/MainActivity: zwm, writeSettings: Hot Fix Settings!
2019-11-01 15:38:55.681 12441-12441/com.tomorrow.hotfixdemo D/MainActivity: zwm, writeSettings success
APP2使用签名1,并且配置了android:sharedUserId="com.tomorrow.uid.test",
MainActivity代码如下:
public class MainActivity extends Activity {
private static final String TAG = "MainActivity";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.d(TAG, "zwm, onCreate");
setContentView(R.layout.activity_main);
getProcessName();
getPidAndUid();
getMemoryInfo();
try {
//获取别的程序的context
Context context = this.createPackageContext("com.tomorrow.hotfixdemo", Context.CONTEXT_IGNORE_SECURITY);
String settings = readSettings(context);
Log.d(TAG, "zwm, ReadSettings: " + settings);
writeSettings(context, "Settings From Network Cache App!");
} catch (PackageManager.NameNotFoundException e) {
e.printStackTrace();
}
}
private void getProcessName() {
String processName = null;
try {
File file = new File("/proc/" + android.os.Process.myPid() + "/" + "cmdline");
BufferedReader mBufferedReader = new BufferedReader(new FileReader(file));
processName = mBufferedReader.readLine().trim();
mBufferedReader.close();
} catch (Exception e) {
e.printStackTrace();
}
Log.d(TAG, "zwm, processName: " + processName);
}
private void getPidAndUid() {
int pid = android.os.Process.myPid();
int uid = android.os.Process.myUid();
Log.d(TAG, "zwm, pid: " + pid + ", uid: " + uid);
}
private void getMemoryInfo(){
Runtime rt = Runtime.getRuntime();
long maxMemory = rt.maxMemory();
Log.d(TAG, "zwm, maxMemory:" + Long.toString(maxMemory/(1024*1024)));
ActivityManager activityManager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
Log.d(TAG, "zwm, getMemoryClass:" + Long.toString(activityManager.getMemoryClass()));
Log.d(TAG, "zwm, getLargeMemoryClass:" + Long.toString(activityManager.getLargeMemoryClass()));
}
public String readSettings(Context context) {
FileInputStream fIn = null;
InputStreamReader isr = null;
char[] inputBuffer = new char[255];
String data = null;
try {
//此处调用并没有区别,但context此时是从别的程序里面获取的
fIn = context.openFileInput("settings.dat");
isr = new InputStreamReader(fIn);
int count = isr.read(inputBuffer);
data = new String(inputBuffer, 0, count);
Log.d(TAG, "zwm, ReadSettings success");
} catch (Exception e) {
e.printStackTrace();
Log.d(TAG, "zwm, ReadSettings fail");
} finally {
if(isr != null) {
try {
isr.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(fIn != null) {
try {
fIn.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return data;
}
public void writeSettings(Context context, String data) {
Log.d(TAG, "zwm, writeSettings: " + data);
FileOutputStream fOut = null;
OutputStreamWriter osw = null;
try {
fOut = context.openFileOutput("settings.dat", MODE_PRIVATE);
//此处调用并没有区别,但context此时是从别的程序里面获取的
osw = new OutputStreamWriter(fOut);
osw.write(data);
osw.flush();
Log.d(TAG, "zwm, writeSettings success");
} catch (Exception e) {
e.printStackTrace();
Log.d(TAG, "zwm, writeSettings fail");
} finally {
if(osw != null) {
try {
osw.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(fOut != null) {
try {
fOut.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
运行输出log如下:
2019-11-01 15:47:08.896 13419-13419/com.tomorrow.testnetworkcache D/MainActivity: zwm, onCreate
2019-11-01 15:47:08.960 13419-13419/com.tomorrow.testnetworkcache D/MainActivity: zwm, processName: com.tomorrow.testnetworkcache
2019-11-01 15:47:08.960 13419-13419/com.tomorrow.testnetworkcache D/MainActivity: zwm, pid: 13419, uid: 10399
2019-11-01 15:47:08.960 13419-13419/com.tomorrow.testnetworkcache D/MainActivity: zwm, maxMemory:256
2019-11-01 15:47:08.960 13419-13419/com.tomorrow.testnetworkcache D/MainActivity: zwm, getMemoryClass:256
2019-11-01 15:47:08.961 13419-13419/com.tomorrow.testnetworkcache D/MainActivity: zwm, getLargeMemoryClass:512
2019-11-01 15:47:08.974 13419-13419/com.tomorrow.testnetworkcache D/MainActivity: zwm, ReadSettings success
2019-11-01 15:47:08.974 13419-13419/com.tomorrow.testnetworkcache D/MainActivity: zwm, ReadSettings: Hot Fix Settings!
2019-11-01 15:47:08.974 13419-13419/com.tomorrow.testnetworkcache D/MainActivity: zwm, writeSettings: Settings From Network Cache App!
2019-11-01 15:47:08.975 13419-13419/com.tomorrow.testnetworkcache D/MainActivity: zwm, writeSettings success
再次运行输出log如下:
2019-11-01 15:47:19.007 13419-13419/com.tomorrow.testnetworkcache D/MainActivity: zwm, onCreate
2019-11-01 15:47:19.042 13419-13419/com.tomorrow.testnetworkcache D/MainActivity: zwm, processName: com.tomorrow.testnetworkcache
2019-11-01 15:47:19.043 13419-13419/com.tomorrow.testnetworkcache D/MainActivity: zwm, pid: 13419, uid: 10399
2019-11-01 15:47:19.043 13419-13419/com.tomorrow.testnetworkcache D/MainActivity: zwm, maxMemory:256
2019-11-01 15:47:19.043 13419-13419/com.tomorrow.testnetworkcache D/MainActivity: zwm, getMemoryClass:256
2019-11-01 15:47:19.043 13419-13419/com.tomorrow.testnetworkcache D/MainActivity: zwm, getLargeMemoryClass:512
2019-11-01 15:47:19.044 13419-13419/com.tomorrow.testnetworkcache D/MainActivity: zwm, ReadSettings success
2019-11-01 15:47:19.044 13419-13419/com.tomorrow.testnetworkcache D/MainActivity: zwm, ReadSettings: Settings From Network Cache App!
2019-11-01 15:47:19.044 13419-13419/com.tomorrow.testnetworkcache D/MainActivity: zwm, writeSettings: Settings From Network Cache App!
2019-11-01 15:47:19.044 13419-13419/com.tomorrow.testnetworkcache D/MainActivity: zwm, writeSettings success
情况2:不同APP使用相同的签名,但是配置了不同的android:sharedUserId属性,共享失败。
APP1使用签名1,并且配置了android:sharedUserId="com.tomorrow.uid.test",
MainActivity代码如下:
public class MainActivity extends Activity {
private static final String TAG = "MainActivity";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Log.d(TAG, "zwm, onCreate");
getProcessName();
getPidAndUid();
getMemoryInfo();
writeSettings(this, "Hot Fix Settings!");
}
private void getProcessName() {
String processName = null;
try {
File file = new File("/proc/" + android.os.Process.myPid() + "/" + "cmdline");
BufferedReader mBufferedReader = new BufferedReader(new FileReader(file));
processName = mBufferedReader.readLine().trim();
mBufferedReader.close();
} catch (Exception e) {
e.printStackTrace();
}
Log.d(TAG, "zwm, processName: " + processName);
}
private void getPidAndUid() {
int pid = android.os.Process.myPid();
int uid = android.os.Process.myUid();
Log.d(TAG, "zwm, pid: " + pid + ", uid: " + uid);
}
private void getMemoryInfo(){
Runtime rt = Runtime.getRuntime();
long maxMemory = rt.maxMemory();
Log.d(TAG, "zwm, maxMemory:" + Long.toString(maxMemory/(1024*1024)));
ActivityManager activityManager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
Log.d(TAG, "zwm, getMemoryClass:" + Long.toString(activityManager.getMemoryClass()));
Log.d(TAG, "zwm, getLargeMemoryClass:" + Long.toString(activityManager.getLargeMemoryClass()));
}
public void writeSettings(Context context, String data) {
Log.d(TAG, "zwm, writeSettings: " + data);
FileOutputStream fOut = null;
OutputStreamWriter osw = null;
try {
//默认建立在data/data/app包名/file/
fOut = context.openFileOutput("settings.dat", MODE_PRIVATE);
osw = new OutputStreamWriter(fOut);
osw.write(data);
osw.flush();
Log.d(TAG, "zwm, writeSettings success");
} catch (Exception e) {
e.printStackTrace();
Log.d(TAG, "zwm, writeSettings fail");
} finally {
if(osw != null) {
try {
osw.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(fOut != null) {
try {
fOut.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
运行输出log如下:
2019-11-01 15:50:19.212 16177-16177/com.tomorrow.hotfixdemo D/MainActivity: zwm, onCreate
2019-11-01 15:50:19.213 16177-16177/com.tomorrow.hotfixdemo D/MainActivity: zwm, processName: com.tomorrow.hotfixdemo
2019-11-01 15:50:19.213 16177-16177/com.tomorrow.hotfixdemo D/MainActivity: zwm, pid: 16177, uid: 10399
2019-11-01 15:50:19.213 16177-16177/com.tomorrow.hotfixdemo D/MainActivity: zwm, maxMemory:256
2019-11-01 15:50:19.214 16177-16177/com.tomorrow.hotfixdemo D/MainActivity: zwm, getMemoryClass:256
2019-11-01 15:50:19.214 16177-16177/com.tomorrow.hotfixdemo D/MainActivity: zwm, getLargeMemoryClass:512
2019-11-01 15:50:19.214 16177-16177/com.tomorrow.hotfixdemo D/MainActivity: zwm, writeSettings: Hot Fix Settings!
2019-11-01 15:50:19.215 16177-16177/com.tomorrow.hotfixdemo D/MainActivity: zwm, writeSettings success
APP2使用签名1,并且配置了android:sharedUserId="com.tomorrow.uid.test123",
MainActivity代码如下:
public class MainActivity extends Activity {
private static final String TAG = "MainActivity";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.d(TAG, "zwm, onCreate");
setContentView(R.layout.activity_main);
getProcessName();
getPidAndUid();
getMemoryInfo();
try {
//获取别的程序的context
Context context = this.createPackageContext("com.tomorrow.hotfixdemo", Context.CONTEXT_IGNORE_SECURITY);
String settings = readSettings(context);
Log.d(TAG, "zwm, ReadSettings: " + settings);
writeSettings(context, "Settings From Network Cache App!");
} catch (PackageManager.NameNotFoundException e) {
e.printStackTrace();
}
}
private void getProcessName() {
String processName = null;
try {
File file = new File("/proc/" + android.os.Process.myPid() + "/" + "cmdline");
BufferedReader mBufferedReader = new BufferedReader(new FileReader(file));
processName = mBufferedReader.readLine().trim();
mBufferedReader.close();
} catch (Exception e) {
e.printStackTrace();
}
Log.d(TAG, "zwm, processName: " + processName);
}
private void getPidAndUid() {
int pid = android.os.Process.myPid();
int uid = android.os.Process.myUid();
Log.d(TAG, "zwm, pid: " + pid + ", uid: " + uid);
}
private void getMemoryInfo(){
Runtime rt = Runtime.getRuntime();
long maxMemory = rt.maxMemory();
Log.d(TAG, "zwm, maxMemory:" + Long.toString(maxMemory/(1024*1024)));
ActivityManager activityManager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
Log.d(TAG, "zwm, getMemoryClass:" + Long.toString(activityManager.getMemoryClass()));
Log.d(TAG, "zwm, getLargeMemoryClass:" + Long.toString(activityManager.getLargeMemoryClass()));
}
public String readSettings(Context context) {
FileInputStream fIn = null;
InputStreamReader isr = null;
char[] inputBuffer = new char[255];
String data = null;
try {
//此处调用并没有区别,但context此时是从别的程序里面获取的
fIn = context.openFileInput("settings.dat");
isr = new InputStreamReader(fIn);
int count = isr.read(inputBuffer);
data = new String(inputBuffer, 0, count);
Log.d(TAG, "zwm, ReadSettings success");
} catch (Exception e) {
e.printStackTrace();
Log.d(TAG, "zwm, ReadSettings fail");
} finally {
if(isr != null) {
try {
isr.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(fIn != null) {
try {
fIn.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return data;
}
public void writeSettings(Context context, String data) {
Log.d(TAG, "zwm, writeSettings: " + data);
FileOutputStream fOut = null;
OutputStreamWriter osw = null;
try {
fOut = context.openFileOutput("settings.dat", MODE_PRIVATE);
//此处调用并没有区别,但context此时是从别的程序里面获取的
osw = new OutputStreamWriter(fOut);
osw.write(data);
osw.flush();
Log.d(TAG, "zwm, writeSettings success");
} catch (Exception e) {
e.printStackTrace();
Log.d(TAG, "zwm, writeSettings fail");
} finally {
if(osw != null) {
try {
osw.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(fOut != null) {
try {
fOut.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
运行输出log如下:
2019-11-01 15:51:00.761 16269-16269/com.tomorrow.testnetworkcache D/MainActivity: zwm, onCreate
2019-11-01 15:51:00.873 16269-16269/com.tomorrow.testnetworkcache D/MainActivity: zwm, processName: com.tomorrow.testnetworkcache
2019-11-01 15:51:00.873 16269-16269/com.tomorrow.testnetworkcache D/MainActivity: zwm, pid: 16269, uid: 10402
2019-11-01 15:51:00.874 16269-16269/com.tomorrow.testnetworkcache D/MainActivity: zwm, maxMemory:256
2019-11-01 15:51:00.874 16269-16269/com.tomorrow.testnetworkcache D/MainActivity: zwm, getMemoryClass:256
2019-11-01 15:51:00.874 16269-16269/com.tomorrow.testnetworkcache D/MainActivity: zwm, getLargeMemoryClass:512
2019-11-01 15:51:00.889 16269-16269/com.tomorrow.testnetworkcache D/MainActivity: zwm, ReadSettings fail
2019-11-01 15:51:00.889 16269-16269/com.tomorrow.testnetworkcache D/MainActivity: zwm, ReadSettings: null
2019-11-01 15:51:00.889 16269-16269/com.tomorrow.testnetworkcache D/MainActivity: zwm, writeSettings: Settings From Network Cache App!
2019-11-01 15:51:00.892 16269-16269/com.tomorrow.testnetworkcache D/MainActivity: zwm, writeSettings fail
2019-11-01 15:51:00.888 16269-16269/com.tomorrow.testnetworkcache W/System.err: java.io.FileNotFoundException: /data/user/0/com.tomorrow.hotfixdemo/files/settings.dat (Permission denied)
2019-11-01 15:51:00.888 16269-16269/com.tomorrow.testnetworkcache W/System.err: at java.io.FileInputStream.open0(Native Method)
2019-11-01 15:51:00.888 16269-16269/com.tomorrow.testnetworkcache W/System.err: at java.io.FileInputStream.open(FileInputStream.java:231)
2019-11-01 15:51:00.888 16269-16269/com.tomorrow.testnetworkcache W/System.err: at java.io.FileInputStream.<init>(FileInputStream.java:165)
2019-11-01 15:51:00.888 16269-16269/com.tomorrow.testnetworkcache W/System.err: at android.app.ContextImpl.openFileInput(ContextImpl.java:608)
2019-11-01 15:51:00.888 16269-16269/com.tomorrow.testnetworkcache W/System.err: at com.tomorrow.testnetworkcache.MainActivity.readSettings(MainActivity.java:89)
2019-11-01 15:51:00.888 16269-16269/com.tomorrow.testnetworkcache W/System.err: at com.tomorrow.testnetworkcache.MainActivity.onCreate(MainActivity.java:46)
- 不同APP的资源目录共享(/data/app/app包名)
情况1:不同APP使用相同的签名,但是配置了不同的android:sharedUserId属性,共享成功。
APP1使用签名1,并且配置了android:sharedUserId="com.tomorrow.uid.test",字符串资源为:
<string name="app_name">HotFixDemo</string>
APP2使用签名1,并且配置了android:sharedUserId="com.tomorrow.uid.test123",
MainActivity代码如下:
public class MainActivity extends Activity {
private static final String TAG = "MainActivity";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.d(TAG, "zwm, onCreate");
setContentView(R.layout.activity_main);
getProcessName();
getPidAndUid();
getMemoryInfo();
try {
//获取别的程序的context
Context context = this.createPackageContext("com.tomorrow.hotfixdemo", Context.CONTEXT_IGNORE_SECURITY);
Resources resources = context.getResources();
int stringId = resources.getIdentifier("app_name", "string", "com.tomorrow.hotfixdemo");
String stringText = resources.getString(stringId);
Log.d(TAG, "zwm, stringText: " + stringText);
} catch (PackageManager.NameNotFoundException e) {
e.printStackTrace();
}
}
private void getProcessName() {
String processName = null;
try {
File file = new File("/proc/" + android.os.Process.myPid() + "/" + "cmdline");
BufferedReader mBufferedReader = new BufferedReader(new FileReader(file));
processName = mBufferedReader.readLine().trim();
mBufferedReader.close();
} catch (Exception e) {
e.printStackTrace();
}
Log.d(TAG, "zwm, processName: " + processName);
}
private void getPidAndUid() {
int pid = android.os.Process.myPid();
int uid = android.os.Process.myUid();
Log.d(TAG, "zwm, pid: " + pid + ", uid: " + uid);
}
private void getMemoryInfo(){
Runtime rt = Runtime.getRuntime();
long maxMemory = rt.maxMemory();
Log.d(TAG, "zwm, maxMemory:" + Long.toString(maxMemory/(1024*1024)));
ActivityManager activityManager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
Log.d(TAG, "zwm, getMemoryClass:" + Long.toString(activityManager.getMemoryClass()));
Log.d(TAG, "zwm, getLargeMemoryClass:" + Long.toString(activityManager.getLargeMemoryClass()));
}
}
运行输出log如下:
2019-11-01 17:36:14.460 2751-2751/com.tomorrow.testnetworkcache D/MainActivity: zwm, onCreate
2019-11-01 17:36:14.611 2751-2751/com.tomorrow.testnetworkcache D/MainActivity: zwm, processName: com.tomorrow.testnetworkcache
2019-11-01 17:36:14.611 2751-2751/com.tomorrow.testnetworkcache D/MainActivity: zwm, pid: 2751, uid: 10404
2019-11-01 17:36:14.611 2751-2751/com.tomorrow.testnetworkcache D/MainActivity: zwm, maxMemory:256
2019-11-01 17:36:14.611 2751-2751/com.tomorrow.testnetworkcache D/MainActivity: zwm, getMemoryClass:256
2019-11-01 17:36:14.612 2751-2751/com.tomorrow.testnetworkcache D/MainActivity: zwm, getLargeMemoryClass:512
2019-11-01 17:36:14.624 2751-2751/com.tomorrow.testnetworkcache D/MainActivity: zwm, stringText: HotFixDemo
情况2:不同APP使用不同的签名,并且配置了不同的android:sharedUserId属性,共享成功。
APP1使用签名1,并且配置了android:sharedUserId="com.tomorrow.uid.test",字符串资源为:
<string name="app_name">三星音乐</string>
APP2使用签名2,并且配置了android:sharedUserId="com.tomorrow.uid.test123",
MainActivity代码如下:
public class MainActivity extends Activity {
private static final String TAG = "MainActivity";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.d(TAG, "zwm, onCreate");
setContentView(R.layout.activity_main);
getProcessName();
getPidAndUid();
getMemoryInfo();
try {
//获取别的程序的context
Context context = this.createPackageContext("com.samsung.android.app.music.chn", Context.CONTEXT_IGNORE_SECURITY);
Resources resources = context.getResources();
int stringId = resources.getIdentifier("app_name", "string", "com.samsung.android.app.music.chn");
String stringText = resources.getString(stringId);
Log.d(TAG, "zwm, stringText: " + stringText);
} catch (PackageManager.NameNotFoundException e) {
e.printStackTrace();
}
}
private void getProcessName() {
String processName = null;
try {
File file = new File("/proc/" + android.os.Process.myPid() + "/" + "cmdline");
BufferedReader mBufferedReader = new BufferedReader(new FileReader(file));
processName = mBufferedReader.readLine().trim();
mBufferedReader.close();
} catch (Exception e) {
e.printStackTrace();
}
Log.d(TAG, "zwm, processName: " + processName);
}
private void getPidAndUid() {
int pid = android.os.Process.myPid();
int uid = android.os.Process.myUid();
Log.d(TAG, "zwm, pid: " + pid + ", uid: " + uid);
}
private void getMemoryInfo(){
Runtime rt = Runtime.getRuntime();
long maxMemory = rt.maxMemory();
Log.d(TAG, "zwm, maxMemory:" + Long.toString(maxMemory/(1024*1024)));
ActivityManager activityManager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
Log.d(TAG, "zwm, getMemoryClass:" + Long.toString(activityManager.getMemoryClass()));
Log.d(TAG, "zwm, getLargeMemoryClass:" + Long.toString(activityManager.getLargeMemoryClass()));
}
}
运行输出log如下:
2019-11-01 17:32:51.642 31444-31444/com.tomorrow.testnetworkcache D/MainActivity: zwm, onCreate
2019-11-01 17:32:51.882 31444-31444/com.tomorrow.testnetworkcache D/MainActivity: zwm, processName: com.tomorrow.testnetworkcache
2019-11-01 17:32:51.882 31444-31444/com.tomorrow.testnetworkcache D/MainActivity: zwm, pid: 31444, uid: 10403
2019-11-01 17:32:51.882 31444-31444/com.tomorrow.testnetworkcache D/MainActivity: zwm, maxMemory:256
2019-11-01 17:32:51.883 31444-31444/com.tomorrow.testnetworkcache D/MainActivity: zwm, getMemoryClass:256
2019-11-01 17:32:51.883 31444-31444/com.tomorrow.testnetworkcache D/MainActivity: zwm, getLargeMemoryClass:512
2019-11-01 17:32:51.914 31444-31444/com.tomorrow.testnetworkcache D/MainActivity: zwm, stringText: 三星音乐
五、运行机制
在多进程模式中,不同进程的组件会拥有独立的虚拟机、Application以及内存空间。
一般来说,使用多进程会造成以下几个方面的问题:
(1)静态成员和单例模式完全失效。
Android为每一个应用分配了一个独立的虚拟机,或者说为每一个进程分配了一个独立的虚拟机,不同的虚拟机在内存分配上有不同的地址空间,这就导致在不同的虚拟机中访问同一个类的对象会产生多份副本。
//AndroidManifest.xml
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.tomorrow.testnetworkcache"
android:sharedUserId="com.tomorrow.uid.test1234567">
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.INTERNET"/>
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:usesCleartextTraffic="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name="com.ryg.dynamicload.DLProxyActivity"
android:label="@string/app_name" >
<intent-filter>
<action android:name="com.ryg.dynamicload.proxy.activity.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
<activity android:name="com.tomorrow.other.TestActivity2"
android:process=":OtherProcess"/>
</application>
</manifest>
//MainActivity
public class MainActivity extends Activity {
private static final String TAG = "MainActivity";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.d(TAG, "zwm, onCreate");
setContentView(R.layout.activity_main);
getProcessName();
getPidAndUid();
getMemoryInfo();
Log.d(TAG, "zwm, TestUtil.value: " + TestUtil.value);
TestUtil.value = 99;
Log.d(TAG, "zwm, TestUtil.value change: " + TestUtil.value);
Log.d(TAG, "zwm, TestUtil instance: " + TestUtil.getInstance());
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
Intent intent = new Intent(MainActivity.this, TestActivity2.class);
startActivity(intent);
}
}, 2000);
}
private void getProcessName() {
String processName = null;
try {
File file = new File("/proc/" + android.os.Process.myPid() + "/" + "cmdline");
BufferedReader mBufferedReader = new BufferedReader(new FileReader(file));
processName = mBufferedReader.readLine().trim();
mBufferedReader.close();
} catch (Exception e) {
e.printStackTrace();
}
Log.d(TAG, "zwm, processName: " + processName);
}
private void getPidAndUid() {
int pid = android.os.Process.myPid();
int uid = android.os.Process.myUid();
Log.d(TAG, "zwm, pid: " + pid + ", uid: " + uid);
}
private void getMemoryInfo(){
Runtime rt = Runtime.getRuntime();
long maxMemory = rt.maxMemory();
Log.d(TAG, "zwm, maxMemory:" + Long.toString(maxMemory/(1024*1024)));
ActivityManager activityManager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
Log.d(TAG, "zwm, getMemoryClass:" + Long.toString(activityManager.getMemoryClass()));
Log.d(TAG, "zwm, getLargeMemoryClass:" + Long.toString(activityManager.getLargeMemoryClass()));
}
}
//TestActivity2
public class TestActivity2 extends Activity {
private static final String TAG = "TestActivity2";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.d(TAG, "zwm, onCreate");
getProcessName();
getPidAndUid();
getMemoryInfo();
Log.d(TAG, "zwm, TestUtil.value: " + TestUtil.value);
Log.d(TAG, "zwm, TestUtil instance: " + TestUtil.getInstance());
}
private void getProcessName() {
String processName = null;
try {
File file = new File("/proc/" + android.os.Process.myPid() + "/" + "cmdline");
BufferedReader mBufferedReader = new BufferedReader(new FileReader(file));
processName = mBufferedReader.readLine().trim();
mBufferedReader.close();
} catch (Exception e) {
e.printStackTrace();
}
Log.d(TAG, "zwm, processName: " + processName);
}
private void getPidAndUid() {
int pid = android.os.Process.myPid();
int uid = android.os.Process.myUid();
Log.d(TAG, "zwm, pid: " + pid + ", uid: " + uid);
}
private void getMemoryInfo(){
Runtime rt = Runtime.getRuntime();
long maxMemory = rt.maxMemory();
Log.d(TAG, "zwm, maxMemory:" + Long.toString(maxMemory/(1024*1024)));
ActivityManager activityManager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
Log.d(TAG, "zwm, getMemoryClass:" + Long.toString(activityManager.getMemoryClass()));
Log.d(TAG, "zwm, getLargeMemoryClass:" + Long.toString(activityManager.getLargeMemoryClass()));
}
}
//TestUtil
public class TestUtil {
public static int value = 10;
private TestUtil() {
}
public static TestUtil getInstance() {
return LazyClass.INSTANCE;
}
private static class LazyClass {
private final static TestUtil INSTANCE = new TestUtil();
}
}
//运行输出log如下:
2019-11-04 10:23:36.548 20794-20794/com.tomorrow.testnetworkcache D/MainActivity: zwm, onCreate
2019-11-04 10:23:36.859 20794-20794/com.tomorrow.testnetworkcache D/MainActivity: zwm, processName: com.tomorrow.testnetworkcache
2019-11-04 10:23:36.860 20794-20794/com.tomorrow.testnetworkcache D/MainActivity: zwm, pid: 20794, uid: 10404
2019-11-04 10:23:36.860 20794-20794/com.tomorrow.testnetworkcache D/MainActivity: zwm, maxMemory:256
2019-11-04 10:23:36.860 20794-20794/com.tomorrow.testnetworkcache D/MainActivity: zwm, getMemoryClass:256
2019-11-04 10:23:36.860 20794-20794/com.tomorrow.testnetworkcache D/MainActivity: zwm, getLargeMemoryClass:512
2019-11-04 10:23:36.861 20794-20794/com.tomorrow.testnetworkcache D/MainActivity: zwm, TestUtil.value: 10
2019-11-04 10:23:36.861 20794-20794/com.tomorrow.testnetworkcache D/MainActivity: zwm, TestUtil.value change: 99
2019-11-04 10:23:36.862 20794-20794/com.tomorrow.testnetworkcache D/MainActivity: zwm, TestUtil instance: com.tomorrow.other.TestUtil@2b7c281
2019-11-04 10:23:40.266 21020-21020/com.tomorrow.testnetworkcache:OtherProcess D/TestActivity2: zwm, onCreate
2019-11-04 10:23:40.268 21020-21020/com.tomorrow.testnetworkcache:OtherProcess D/TestActivity2: zwm, processName: com.tomorrow.testnetworkcache:OtherProcess
2019-11-04 10:23:40.268 21020-21020/com.tomorrow.testnetworkcache:OtherProcess D/TestActivity2: zwm, pid: 21020, uid: 10404
2019-11-04 10:23:40.268 21020-21020/com.tomorrow.testnetworkcache:OtherProcess D/TestActivity2: zwm, maxMemory:256
2019-11-04 10:23:40.269 21020-21020/com.tomorrow.testnetworkcache:OtherProcess D/TestActivity2: zwm, getMemoryClass:256
2019-11-04 10:23:40.269 21020-21020/com.tomorrow.testnetworkcache:OtherProcess D/TestActivity2: zwm, getLargeMemoryClass:512
2019-11-04 10:23:40.269 21020-21020/com.tomorrow.testnetworkcache:OtherProcess D/TestActivity2: zwm, TestUtil.value: 10
2019-11-04 10:23:40.270 21020-21020/com.tomorrow.testnetworkcache:OtherProcess D/TestActivity2: zwm, TestUtil instance: com.tomorrow.other.TestUtil@35aac08
(2)线程同步机制完全失效。
该问题本质上跟(1)是类似的,既然都不是同一块内存了,那么不管是锁对象还是锁全局类都无法保证线程同步,因为不同进程锁的不是同一个对象。
//AndroidManifest
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.tomorrow.testnetworkcache"
android:sharedUserId="com.tomorrow.uid.test12345">
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:usesCleartextTraffic="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name="com.tomorrow.other.TestActivity2"
android:process=":OtherProcess"/>
</application>
</manifest>
//MainActivity
public class MainActivity extends Activity {
private static final String TAG = "MainActivity";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.d(TAG, "zwm, onCreate");
setContentView(R.layout.activity_main);
getProcessName();
getPidAndUid();
getMemoryInfo();
new Thread(new Runnable() {
@Override
public void run() {
Log.d(TAG, "zwm, thread: " + Thread.currentThread().getName() + " run, TestUtil.class: " + TestUtil.class);
synchronized (TestUtil.class) {
Log.d(TAG, "zwm, thread: " + Thread.currentThread().getName() + " acquire lock");
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
Log.d(TAG, "zwm, thread: " + Thread.currentThread().getName() + " release lock");
}
}
}).start();
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
Intent intent = new Intent(MainActivity.this, TestActivity2.class);
startActivity(intent);
}
}, 1000);
}
private void getProcessName() {
String processName = null;
try {
File file = new File("/proc/" + android.os.Process.myPid() + "/" + "cmdline");
BufferedReader mBufferedReader = new BufferedReader(new FileReader(file));
processName = mBufferedReader.readLine().trim();
mBufferedReader.close();
} catch (Exception e) {
e.printStackTrace();
}
Log.d(TAG, "zwm, processName: " + processName);
}
private void getPidAndUid() {
int pid = android.os.Process.myPid();
int uid = android.os.Process.myUid();
Log.d(TAG, "zwm, pid: " + pid + ", uid: " + uid);
}
private void getMemoryInfo(){
Runtime rt = Runtime.getRuntime();
long maxMemory = rt.maxMemory();
Log.d(TAG, "zwm, maxMemory:" + Long.toString(maxMemory/(1024*1024)));
ActivityManager activityManager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
Log.d(TAG, "zwm, getMemoryClass:" + Long.toString(activityManager.getMemoryClass()));
Log.d(TAG, "zwm, getLargeMemoryClass:" + Long.toString(activityManager.getLargeMemoryClass()));
}
}
//TestActivity2
public class TestActivity2 extends Activity {
private static final String TAG = "TestActivity2";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.d(TAG, "zwm, onCreate");
getProcessName();
getPidAndUid();
getMemoryInfo();
new Thread(new Runnable() {
@Override
public void run() {
Log.d(TAG, "zwm, thread: " + Thread.currentThread().getName() + " run, TestUtil.class: " + TestUtil.class);
synchronized (TestUtil.class) {
Log.d(TAG, "zwm, thread: " + Thread.currentThread().getName() + " acquire lock");
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
Log.d(TAG, "zwm, thread: " + Thread.currentThread().getName() + " release lock");
}
}
}).start();
}
private void getProcessName() {
String processName = null;
try {
File file = new File("/proc/" + android.os.Process.myPid() + "/" + "cmdline");
BufferedReader mBufferedReader = new BufferedReader(new FileReader(file));
processName = mBufferedReader.readLine().trim();
mBufferedReader.close();
} catch (Exception e) {
e.printStackTrace();
}
Log.d(TAG, "zwm, processName: " + processName);
}
private void getPidAndUid() {
int pid = android.os.Process.myPid();
int uid = android.os.Process.myUid();
Log.d(TAG, "zwm, pid: " + pid + ", uid: " + uid);
}
private void getMemoryInfo(){
Runtime rt = Runtime.getRuntime();
long maxMemory = rt.maxMemory();
Log.d(TAG, "zwm, maxMemory:" + Long.toString(maxMemory/(1024*1024)));
ActivityManager activityManager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
Log.d(TAG, "zwm, getMemoryClass:" + Long.toString(activityManager.getMemoryClass()));
Log.d(TAG, "zwm, getLargeMemoryClass:" + Long.toString(activityManager.getLargeMemoryClass()));
}
}
//TestUtil
public class TestUtil {
}
//运行输出log如下:
2019-11-04 10:40:11.491 26526-26526/com.tomorrow.testnetworkcache D/MainActivity: zwm, onCreate
2019-11-04 10:40:11.637 26526-26526/com.tomorrow.testnetworkcache D/MainActivity: zwm, processName: com.tomorrow.testnetworkcache
2019-11-04 10:40:11.637 26526-26526/com.tomorrow.testnetworkcache D/MainActivity: zwm, pid: 26526, uid: 10399
2019-11-04 10:40:11.637 26526-26526/com.tomorrow.testnetworkcache D/MainActivity: zwm, maxMemory:256
2019-11-04 10:40:11.637 26526-26526/com.tomorrow.testnetworkcache D/MainActivity: zwm, getMemoryClass:256
2019-11-04 10:40:11.637 26526-26526/com.tomorrow.testnetworkcache D/MainActivity: zwm, getLargeMemoryClass:512
2019-11-04 10:40:11.639 26526-26643/com.tomorrow.testnetworkcache D/MainActivity: zwm, thread: Thread-8 run, TestUtil.class: class com.tomorrow.other.TestUtil
2019-11-04 10:40:11.639 26526-26643/com.tomorrow.testnetworkcache D/MainActivity: zwm, thread: Thread-8 acquire lock
2019-11-04 10:40:13.155 26734-26734/com.tomorrow.testnetworkcache:OtherProcess D/TestActivity2: zwm, onCreate
2019-11-04 10:40:13.156 26734-26734/com.tomorrow.testnetworkcache:OtherProcess D/TestActivity2: zwm, processName: com.tomorrow.testnetworkcache:OtherProcess
2019-11-04 10:40:13.156 26734-26734/com.tomorrow.testnetworkcache:OtherProcess D/TestActivity2: zwm, pid: 26734, uid: 10399
2019-11-04 10:40:13.156 26734-26734/com.tomorrow.testnetworkcache:OtherProcess D/TestActivity2: zwm, maxMemory:256
2019-11-04 10:40:13.156 26734-26734/com.tomorrow.testnetworkcache:OtherProcess D/TestActivity2: zwm, getMemoryClass:256
2019-11-04 10:40:13.156 26734-26734/com.tomorrow.testnetworkcache:OtherProcess D/TestActivity2: zwm, getLargeMemoryClass:512
2019-11-04 10:40:13.157 26734-26782/com.tomorrow.testnetworkcache:OtherProcess D/TestActivity2: zwm, thread: Thread-6 run, TestUtil.class: class com.tomorrow.other.TestUtil
2019-11-04 10:40:13.157 26734-26782/com.tomorrow.testnetworkcache:OtherProcess D/TestActivity2: zwm, thread: Thread-6 acquire lock
2019-11-04 10:40:16.646 26526-26643/com.tomorrow.testnetworkcache D/MainActivity: zwm, thread: Thread-8 release lock
2019-11-04 10:40:18.158 26734-26782/com.tomorrow.testnetworkcache:OtherProcess D/TestActivity2: zwm, thread: Thread-6 release lock
(3)SharedPreferences可靠性下降。
因为SharedPreferences底层是通过读/写XML文件来实现,并发读/写都有可能出问题。
(4)SQLite容易被锁。
由于每个进程可能会使用各自的SQLOpenHelper实例,如果两个进程同时对数据库操作,则会发生SQLiteDatabaseLockedException等异常。解决方法是,使用ContentProvider来实现。
(5)Application会多次创建。
当一个组件跑在一个新的进程中的时候,由于系统要在创建新的进程的同时分配独立的虚拟机,所以这个过程其实就是启动一个应用的过程,相当于系统又把这个应用重新启动了一遍,因此会创建新的Application,并调用其onCreate方法。因此在Application中需要根据当前进程名称,按需进行初始化。
//AndroidManifest
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.tomorrow.testnetworkcache"
android:sharedUserId="com.tomorrow.uid.test12345">
<application
android:name="com.tomorrow.other.CustomApplication"
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:usesCleartextTraffic="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name="com.tomorrow.other.TestActivity2"
android:process=":OtherProcess"/>
</application>
</manifest>
//CustomApplication
public class CustomApplication extends Application {
private static final String TAG = "CustomApplication";
@Override
public void onCreate() {
super.onCreate();
Log.d(TAG, "zwm, onCreate");
printProcessName();
}
private void printProcessName() {
String processName = null;
try {
File file = new File("/proc/" + android.os.Process.myPid() + "/" + "cmdline");
BufferedReader mBufferedReader = new BufferedReader(new FileReader(file));
processName = mBufferedReader.readLine().trim();
mBufferedReader.close();
} catch (Exception e) {
e.printStackTrace();
}
Log.d(TAG, "zwm, processName: " + processName);
}
}
//MainActivity
public class MainActivity extends Activity {
private static final String TAG = "MainActivity";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.d(TAG, "zwm, onCreate");
setContentView(R.layout.activity_main);
getProcessName();
getPidAndUid();
getMemoryInfo();
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
Intent intent = new Intent(MainActivity.this, TestActivity2.class);
startActivity(intent);
}
}, 1000);
}
private void getProcessName() {
String processName = null;
try {
File file = new File("/proc/" + android.os.Process.myPid() + "/" + "cmdline");
BufferedReader mBufferedReader = new BufferedReader(new FileReader(file));
processName = mBufferedReader.readLine().trim();
mBufferedReader.close();
} catch (Exception e) {
e.printStackTrace();
}
Log.d(TAG, "zwm, processName: " + processName);
}
private void getPidAndUid() {
int pid = android.os.Process.myPid();
int uid = android.os.Process.myUid();
Log.d(TAG, "zwm, pid: " + pid + ", uid: " + uid);
}
private void getMemoryInfo(){
Runtime rt = Runtime.getRuntime();
long maxMemory = rt.maxMemory();
Log.d(TAG, "zwm, maxMemory:" + Long.toString(maxMemory/(1024*1024)));
ActivityManager activityManager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
Log.d(TAG, "zwm, getMemoryClass:" + Long.toString(activityManager.getMemoryClass()));
Log.d(TAG, "zwm, getLargeMemoryClass:" + Long.toString(activityManager.getLargeMemoryClass()));
}
}
//TestActivity2
public class TestActivity2 extends Activity {
private static final String TAG = "TestActivity2";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.d(TAG, "zwm, onCreate");
getProcessName();
getPidAndUid();
getMemoryInfo();
}
private void getProcessName() {
String processName = null;
try {
File file = new File("/proc/" + android.os.Process.myPid() + "/" + "cmdline");
BufferedReader mBufferedReader = new BufferedReader(new FileReader(file));
processName = mBufferedReader.readLine().trim();
mBufferedReader.close();
} catch (Exception e) {
e.printStackTrace();
}
Log.d(TAG, "zwm, processName: " + processName);
}
private void getPidAndUid() {
int pid = android.os.Process.myPid();
int uid = android.os.Process.myUid();
Log.d(TAG, "zwm, pid: " + pid + ", uid: " + uid);
}
private void getMemoryInfo(){
Runtime rt = Runtime.getRuntime();
long maxMemory = rt.maxMemory();
Log.d(TAG, "zwm, maxMemory:" + Long.toString(maxMemory/(1024*1024)));
ActivityManager activityManager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
Log.d(TAG, "zwm, getMemoryClass:" + Long.toString(activityManager.getMemoryClass()));
Log.d(TAG, "zwm, getLargeMemoryClass:" + Long.toString(activityManager.getLargeMemoryClass()));
}
}
//TestUtil
public class TestUtil {
}
//运行输出log如下:
2019-11-04 11:07:47.070 31540-31540/com.tomorrow.testnetworkcache D/CustomApplication: zwm, onCreate
2019-11-04 11:07:47.071 31540-31540/com.tomorrow.testnetworkcache D/CustomApplication: zwm, processName: com.tomorrow.testnetworkcache
2019-11-04 11:07:47.114 31540-31540/com.tomorrow.testnetworkcache D/MainActivity: zwm, onCreate
2019-11-04 11:07:47.218 31540-31540/com.tomorrow.testnetworkcache D/MainActivity: zwm, processName: com.tomorrow.testnetworkcache
2019-11-04 11:07:47.219 31540-31540/com.tomorrow.testnetworkcache D/MainActivity: zwm, pid: 31540, uid: 10399
2019-11-04 11:07:47.219 31540-31540/com.tomorrow.testnetworkcache D/MainActivity: zwm, maxMemory:256
2019-11-04 11:07:47.219 31540-31540/com.tomorrow.testnetworkcache D/MainActivity: zwm, getMemoryClass:256
2019-11-04 11:07:47.219 31540-31540/com.tomorrow.testnetworkcache D/MainActivity: zwm, getLargeMemoryClass:512
2019-11-04 11:07:48.599 31564-31564/com.tomorrow.testnetworkcache:OtherProcess D/CustomApplication: zwm, onCreate
2019-11-04 11:07:48.600 31564-31564/com.tomorrow.testnetworkcache:OtherProcess D/CustomApplication: zwm, processName: com.tomorrow.testnetworkcache:OtherProcess
2019-11-04 11:07:48.645 31564-31564/com.tomorrow.testnetworkcache:OtherProcess D/TestActivity2: zwm, onCreate
2019-11-04 11:07:48.645 31564-31564/com.tomorrow.testnetworkcache:OtherProcess D/TestActivity2: zwm, processName: com.tomorrow.testnetworkcache:OtherProcess
2019-11-04 11:07:48.646 31564-31564/com.tomorrow.testnetworkcache:OtherProcess D/TestActivity2: zwm, pid: 31564, uid: 10399
2019-11-04 11:07:48.646 31564-31564/com.tomorrow.testnetworkcache:OtherProcess D/TestActivity2: zwm, maxMemory:256
2019-11-04 11:07:48.646 31564-31564/com.tomorrow.testnetworkcache:OtherProcess D/TestActivity2: zwm, getMemoryClass:256
2019-11-04 11:07:48.646 31564-31564/com.tomorrow.testnetworkcache:OtherProcess D/TestActivity2: zwm, getLargeMemoryClass:512