A lot of knowledge is known without knowing why, and that may be the difference between a genius and a novice.

Recently, a problem was found in the investigation: a scheduled task started in the Application was called several times when it was running, which was very weird. Finally, it was found to be a pit left by predecessors, because we did not know the reason of android: Process.

Android: process attribute

Android: Process attribute, I believe everyone is familiar with, Android official website is explained in this way:

By default, all components of the same application run in the same process, and most applications do not change this. However, if you find that you need to control the process to which a component belongs, you can do so in the manifest file.

The manifest file entries -,,, and – for various component elements support the Android: Process attribute, which specifies in which process the component should run. You can set this property so that each component runs in its own process, or so that some components share a process and others do not. In addition, you can set Android: Process to run components from different applications in the same process, but only if the applications share the same Linux user ID and sign with the same certificate.

In addition, the element supports the Android: Process attribute to set default values that apply to all components.

Android may decide to shut down a process at a certain point if memory runs low and memory is needed by other processes that provide more urgent services to users. Application components running in the terminated process are also destroyed. When these components need to run again, the system restarts the process for them.

When deciding which processes to kill, the Android system weighs their relative importance to the user. For example, it is more likely to close a hosted Activity process that is no longer visible on the screen than a process that hosts a visible Activity. Therefore, the decision whether to terminate a process depends on the state of the components running in that process. Next, we describe the rules for deciding to terminate a process.

When you need to use a new process, you can use the Android: Process property. If the process name is set to start with a colon, the new process is private to the application and will be created when it is needed or the service needs to run in the new process. If the process name starts with a character and complies with the Android package name specification (com.roger, etc.), the service will run in a global process with that name, provided it has the appropriate permissions. If it starts with a number (e.g. 1Remote.com) or does not conform to the Android package name specification (e.g. Remote), an error will be displayed at compile time (INSTALL_PARSE_FAILED_MANIFEST_MALFORMED). Creating a new process allows components in different applications to share a process, reducing resource usage. See the differences between blog: APK, Task, Android: Process and Android :sharedUserId

The important thing is that because the Android: Process property is set to run the component into another process, equivalent to another Application, a new instance of Application will also be created in another thread. Therefore, onCreate of Application will be called every time a new process is created. If you have a lot of initialization in your Application’s onCreate and need to separate it by process, you need to pay special attention.

Let’s go to the Framework to see the logic of creating a process, please open Lao Luo’s blog: Android system in a new process to start the process of custom service (startService) principle analysis

Introduced the new process to start the process, which we see key Step 17. ActivityThread. HandleCreateService

public final class ActivityThread { ...... private final void handleCreateService(CreateServiceData data) { // If we are getting ready to gc after going to the background, well // we are back active so skip it. unscheduleGcIdler(); LoadedApk packageInfo = getPackageInfoNoCheck( data.info.applicationInfo); Service service = null; try { java.lang.ClassLoader cl = packageInfo.getClassLoader(); service = (Service) cl.loadClass(data.info.name).newInstance(); } catch (Exception e) { if (! mInstrumentation.onException(service, e)) { throw new RuntimeException( "Unable to instantiate service " + data.info.name + ": " + e.toString(), e); } } try { if (localLOGV) Slog.v(TAG, "Creating service " + data.info.name); ContextImpl context = new ContextImpl(); context.init(packageInfo, null, this); Application app = packageInfo.makeApplication(false, mInstrumentation); context.setOuterContext(service); service.attach(context, this, data.info.name, data.token, app, ActivityManagerNative.getDefault()); service.onCreate(); mServices.put(data.token, service); try { ActivityManagerNative.getDefault().serviceDoneExecuting( data.token, 0, 0, 0); } catch (RemoteException e) { // nothing to do. } } catch (Exception e) { if (! mInstrumentation.onException(service, e)) { throw new RuntimeException( "Unable to create service " + data.info.name + ": " + e.toString(), e); }}}... }Copy the code

See this line Application app = packageInfo. MakeApplication (false, mInstrumentation); This is where the Application is created.

The solution

Gets the name of the currently running process:

Plan 1

public static String getProcessName(Context cxt, int pid) {  
    ActivityManager am = (ActivityManager) cxt.getSystemService(Context.ACTIVITY_SERVICE);  
    List runningApps = am.getRunningAppProcesses();  
    if (runningApps == null) {  
        return null;  
    }  
    for (RunningAppProcessInfo procInfo : runningApps) {  
        if (procInfo.pid == pid) {  
            return procInfo.processName;  
        }  
    }  
    return null;  
}  
Copy the code

The current online mainstream approach is not as efficient as Option 2, thanks to Option 2 provided by Forrest

Scheme 2

public static String getProcessName() { try { File file = new File("/proc/" + android.os.Process.myPid() + "/" + "cmdline"); BufferedReader mBufferedReader = new BufferedReader(new FileReader(file)); String processName = mBufferedReader.readLine().trim(); mBufferedReader.close(); return processName; } catch (Exception e) { e.printStackTrace(); return null; }}Copy the code

Then get the process name in Application onCreate and make a judgment, for example:

String processName = getProcessName(this, android.os.Process.myPid()); if (! Textutils.isempty (processName) && processname.equals (this.getpackagename ())) {// determine the processName and ensure that only the main process runs // the main process initializes the logic.... }Copy the code

conclusion

Knowing what it is and why it is, is the magic weapon to summarize and improve. Hope to help students in need 🙂

Have a good day ~

reference

Blog.csdn.net/jason0539/a…

Analysis of the principle of starting startService in a new process of Android system

Apk, Task, Android: Process and Android :sharedUserId