IPC机制 -- 基础知识 -- 多进程模式

一、概念

进程与线程:
线程是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
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 157,198评论 4 359
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 66,663评论 1 290
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 106,985评论 0 237
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,673评论 0 202
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 51,994评论 3 285
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,399评论 1 211
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,717评论 2 310
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,407评论 0 194
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,112评论 1 239
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,371评论 2 241
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,891评论 1 256
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,255评论 2 250
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,881评论 3 233
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,010评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,764评论 0 192
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,412评论 2 269
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,299评论 2 260