A new method to improve the survival rate of Android application processes (Part 1)

A new method to improve the survival rate of Android application processes (Part 1)

[[179902]]

Basics

Android process priority

1 General classification of process priority levels

  • Activate process
  • Visible Process
  • Service process
  • Background process
  • Empty process

2 Service Skills

  • onStartCommand returns START_STICKY
  • startself in onDestroy
  • Service background to front, setForground(true)
  • android:persistent = "true"

3 Process priority number

ProcessList.java

  1. // Adjustment used in certain places where we don't know it yet.
  2. // (Generally this is something that is going to be cached, but we
  3. // don't know the exact value in the cached range to assign yet.)
  4. static final int UNKNOWN_ADJ = 16;
  5.   
  6. // This is a process only hosting activities that are not visible,
  7. // so it can be killed without any disruption.
  8. static final int CACHED_APP_MAX_ADJ = 15;
  9. static final int CACHED_APP_MIN_ADJ = 9;
  10.   
  11. // The B list of SERVICE_ADJ -- these are the old and decrepit  
  12. // services that aren't as shiny and interesting as the ones in the A list.
  13. static final int SERVICE_B_ADJ = 8;
  14.   
  15. // This is the process of the previous application that the user was in .
  16. // This process is kept above other things, because it is very common to  
  17. // switch back to the previous app. This is important both for recent
  18. // task switch (toggling between the two top recent apps) as well as normal
  19. // UI flow such as clicking on a URI in the e-mail app to   view   in the browser,
  20. // and   then pressing back to   return   to e-mail.
  21. static final int PREVIOUS_APP_ADJ = 7;
  22.   
  23. // This is a process holding the home application -- we want to try  
  24. // avoid killing it, even if it would normally be in the background,
  25. // because the user interacts with it so much.
  26. static final int HOME_APP_ADJ = 6;
  27.   
  28. // This is a process holding an application service -- killing it will not  
  29. // have much of an impact as far as the user   is concerned.
  30. static final int SERVICE_ADJ = 5;
  31.   
  32. // This is a process with a heavy-weight application. It is   in the
  33. // background, but we want to try to avoid killing it. Value set   in  
  34. // system/rootdir/init.rc on startup.
  35. static final int HEAVY_WEIGHT_APP_ADJ = 4;
  36.   
  37. // This is a process currently hosting a backup operation. Killing it
  38. // is   not entirely fatal but is generally a bad idea.
  39. static final int BACKUP_APP_ADJ = 3;
  40.   
  41. // This is a process only hosting components that are perceptible to the
  42. // user , and we really want to avoid killing them, but they are not  
  43. // immediately visible. An example is background music playback.
  44. static final int PERCEPTIBLE_APP_ADJ = 2;
  45.   
  46. // This is a process only hosting activities that are visible to the
  47. // user , so we 'd prefer they don' t disappear.
  48. static final int VISIBLE_APP_ADJ = 1;
  49.   
  50. // This is the process running the current foreground app. We'd really
  51. // rather not kill it!
  52. static final int FOREGROUND_APP_ADJ = 0;
  53.   
  54. // This is a process that the system or a persistent process has bound to ,
  55. // and indicated it is important.
  56. static final int PERSISTENT_SERVICE_ADJ = -11;
  57.   
  58. // This is a system persistent process, such as telephony. Definitely
  59. // don't want to kill it, but doing so is   not completely fatal.
  60. static final int PERSISTENT_PROC_ADJ = -12;
  61.   
  62. // The system process runs at the default adjustment.
  63. static final int SYSTEM_ADJ = -16;
  64.   
  65. // Special code for native processes that are not being managed by the system (so
  66. // don't have an oom adj assigned by the system).
  67. static final int NATIVE_ADJ = -17;

Android Low Memory Killer

When the Android system is short of memory, the system will kill some processes to free up space. The life and death of processes is determined by LMK, which is the Low Memory Killer in the Android system. It is based on the Linux OOM mechanism. Its threshold is defined in the lowmemorykiller file shown below. Of course, it can also be customized through the system's init.rc.

lowmemorykiller.c

  1. static uint32_t lowmem_debug_level = 1;
  2. static   int lowmem_adj[6] = {
  3. 0,
  4. 1,
  5. 6,
  6. 12,
  7. };
  8. static   int lowmem_adj_size = 4;
  9. static   int lowmem_minfree[6] = {
  10. 3 * 512, /* 6MB */
  11. 2 * 1024, /* 8MB */
  12. 4 * 1024, /* 16MB */
  13. 16 * 1024, /* 64MB */
  14. };
  15. static   int lowmem_minfree_size = 4;

① In Low Memory Killer, the process to be killed is determined by the oom_adj of the process and the size of the memory occupied. The smaller the oom_adj value, the less likely it is to be killed. Among them, lowmem_minfree is the timing of killing the process. Who is killed depends on lowmem_adj. For the specific meaning, please refer to the above description of Android process priority.

② In init.rc, the oom_adj of the init process (system process) is defined as -16, which cannot be killed (the PID of init is 1), and the foreground process is 0 (the foreground process here refers to the process where the user's currently using Activity is located). When the user presses the Home button to return to the desktop, the priority is 6, and the ordinary Service process is 8.

init.rc

  1. # Set init and its forked children's oom_adj.
  2. write /proc/1/oom_adj -16

For the specific implementation principle of Low Memory Killer, please refer to Ref-2.

View the process of an App

Steps (Connect your phone to PC)

  1. adb shell
  2. ps | grep process name
  3. cat /proc/pid/oom_adj //where pid is the process number obtained by grep above

Linux AM Command

am command: In the Android system, you can use adb shell to start an Activity, Service, make a call, start a browser, and other Android commands. The source code is in Am.java. Executing the am command in a shell environment actually starts a thread to execute the main function (main method) in Am.java. The parameters following the am command will be passed to the main function as runtime parameters, which are mainly implemented in the run method of Am.java.

Make a call

Command: am start -a android.intent.action.CALL -d tel:phone number

Example: am start -a android.intent.action.CALL -d tel:10086

Open a web page

Command: am start -a android.intent.action.VIEW -d URL

Example: am start -a android.intent.action.VIEW -d http://www.skyseraph.com

Start a service

Command: am startservice <service name>

Example: am startservice -n com.android.music/ com.android.music.MediaPlaybackService

NotificationListenerService

“A service that receives calls from the system when new notifications are posted or removed, or their ranking changed.” From Google

Used to monitor the sending, removal and ranking position changes of notifications. If we register this service, when any notification of the system arrives or is removed, we can monitor it through this service, and even do some management work.

Android account and synchronization mechanism

This is relatively obscure knowledge in Android. Please refer to Ref 3 /4 /5 for details.

Android multi-process

  • Implementation: android:process
  • Benefits: An independent process can make full use of its own RAM budget, leaving more room for the main process to handle resources. In addition, the operating system treats processes running in different components differently. This means that not all processes will be killed when the system runs into low available memory conditions.
  • Big gotcha: Each process will have its own instance of the Dalvik VM, which means you can't share data across those instances, at least not in the traditional sense. For example, static fields will have their own value in each process, not just one value as you'd like to believe.
  • For more details, please refer to Ref 9

Existing methods

Network connection keep alive method

A. GCM

B. Public third-party push channels (such as pigeons)

C. It communicates with the server through polling or long connection

For specific implementation, please refer to WeChat architect Yang Ganrong's "WeChat Android client background keep alive experience sharing" (Ref-1).

Dual service (notification bar) to increase process priority

Idea: (API level > 18 )

  • When the application starts, start a fake Service (FakeService), startForeground(), and pass an empty Notification
  • Start the real Service (AlwaysLiveService), startForeground(), note that the Notification ID must be the same
  • FakeService stopForeground()

Effect: Viewed through adb, the process number of the service running in the background becomes 1 (the priority is second only to the foreground process)

Risk: A vulnerability in the Android system foreground service, which may be fixed in systems above 6.0

Implementation: The core code is as follows

  • AlwaysLiveService resident memory service
  1. @Override
  2. public   int onStartCommand(Intent intent, int flags, int startId) {
  3. startForeground(R.id.notify, new Notification());
  4. startService(new Intent(this, FakeService.class));
  5. return super.onStartCommand(intent, flags, startId);
  6. }
  • FakeService temporary service
  1. public class FakeService extends Service {
  2. @Nullable
  3. @Override
  4. public IBinder onBind(Intent intent) {
  5. return   null ;
  6. }
  7.   
  8. @Override
  9. public   int onStartCommand(Intent intent, int flags, int startId) {
  10. startForeground(R.id.notify, new Notification());
  11. stopSelf();
  12. return super.onStartCommand(intent, flags, startId);
  13. }
  14.   
  15. @Override
  16. public void onDestroy() {
  17. stopForeground( true );
  18. super.onDestroy();
  19. }
  20. }

Service is started in time

AlarmReceiver, ConnectReceiver, BootReceiver, etc.

  • Service settings (see the basics above)
  • Restart the service by monitoring system broadcasts, such as booting, locking the screen, and lighting the screen
  • Start the service through the alarm timer

Daemon/process mutual pull

When analyzing the 360 ​​Mobile Assistant app, it was found that it has N multiple processes. After a process is killed, it will be pulled up by other processes that have not been killed. This is also a way of thinking, although it is a bit rogue~

There are generally two ways to daemonize:

  • Multiple Java process daemons pull each other
  • The underlying C daemon process pulls up the App upper layer/Java process

Linux Am command to start background process

A low-level implementation method to prevent the process from being killed. There may be compatibility issues on Android 4.4 and above. For details, please refer to Ref-7

NotificationListenerServiceNotification

A system startup method that requires the user to allow specific permissions, for systems above 4.3

Front desk floating window

A friend suggested launching a non-interactive floating window after exiting the application. I personally think this method is ineffective. Readers who are interested can try it.

New method (AccountSync)

Ideas

Use the account and synchronization mechanism provided by the Android system to achieve

Effect

  • Through adb viewing, the process number of the service running in the background becomes 1 (the priority is second only to the foreground process), which can increase the process priority. The comparison is as follows

Normal situation

After using AccountSyncAdapter method

  • After the process is killed by the system, it can be started by syn

risk

  • The SyncAdapter time progress is not high. It is often adjusted later because the phone is in sleep mode. The minimum synchronization interval is 1 minute.
  • Users can stop or delete them individually. Some mobile phone accounts are not synchronized by default and need to be enabled manually.

Implementation (core code)

1 Establishing a data synchronization system (ContentProvider)

A ContentProvider is used for data synchronization. Since there is no actual data synchronization, an empty ContentProvider can be directly created here.

  1. public class XXAccountProvider extends ContentProvider {
  2. public   static final String AUTHORITY = "Package name.provider" ;
  3. public   static final String CONTENT_URI_BASE = "content://" + AUTHORITY;
  4. public   static final String TABLE_NAME = "data" ;
  5. public   static final Uri CONTENT_URI = Uri.parse(CONTENT_URI_BASE + "/" + TABLE_NAME);
  6.   
  7. @Override
  8. public boolean onCreate() {
  9. return   true ;
  10. }
  11.   
  12. @Nullable
  13. @Override
  14. public   Cursor query(Uri uri, String[] projection, String selection,
  15. String[] selectionArgs, String sortOrder) {
  16. return   null ;
  17. }
  18.   
  19. @Nullable
  20. @Override
  21. public String getType(Uri uri) {
  22. return new String();
  23. }
  24.   
  25. @Nullable
  26. @Override
  27. public Uri insert (Uri uri, ContentValues ​​values ) {
  28. return   null ;
  29. }
  30.   
  31. @Override
  32. public   int   delete (Uri uri, String selection, String[] selectionArgs) {
  33. return 0;
  34. }
  35.   
  36. @Override
  37. public   int   update (Uri uri, ContentValues ​​values ​​, String selection, String[] selectionArgs) {
  38. return 0;
  39. }
  40. }

Then declare it in the Manifest

  1. <provider
  2. android: name = "**.XXAccountProvider"  
  3. android:authorities= "@string/account_auth_provider"  
  4. android:exported= "false"  
  5. android:syncable= "true" />

2. Establishing the Sync System (SyncAdapter)

After implementing the SyncAdapter system service, use the system timer to update the program data ContentProvider. The specific steps are:

  • Creating a Sync Service
  1. public class XXSyncService extends Service {
  2. private static final Object sSyncAdapterLock = new Object();
  3. private static XXSyncAdapter sSyncAdapter = null ;
  4. @Override
  5. public void onCreate() {
  6. synchronized (sSyncAdapterLock) {
  7. if (sSyncAdapter == null ) {
  8. sSyncAdapter = new XXSyncAdapter(getApplicationContext(), true );
  9. }
  10. }
  11. }
  12.   
  13. @Override
  14. public IBinder onBind(Intent intent) {
  15. return sSyncAdapter.getSyncAdapterBinder();
  16. }
  17.   
  18. static class XXSyncAdapter extends AbstractThreadedSyncAdapter {
  19. public XXSyncAdapter(Context context, boolean autoInitialize) {
  20. super(context, autoInitialize);
  21. }
  22. @Override
  23. public void onPerformSync(Account account, Bundle extras, String authority, ContentProviderClient provider, SyncResult syncResult) {
  24. getContext().getContentResolver().notifyChange(XXAccountProvider.CONTENT_URI, null , false );
  25. }
  26. }
  27. }
  • Declare Sync Service
  1. <service
  2. android: name = "**.XXSyncService"  
  3. android:exported= "true"  
  4. android:process= ":core" >
  5. <intent-filter>
  6. < action  
  7. android: name = "android.content.SyncAdapter" />
  8. </intent-filter>
  9. <meta-data
  10. android: name = "android.content.SyncAdapter"  
  11. android:resource= "@xml/sync_adapter" />
  12. </service>

Where sync_adapter is:

  1. <sync-adapter xmlns:android= "http://schemas.android.com/apk/res/android"  
  2. android:accountType= "@string/account_auth_type"  
  3. android:allowParallelSyncs= "false"  
  4. android:contentAuthority= "@string/account_auth_provide"  
  5. android:isAlwaysSyncable= "true"  
  6. android:supportsUploading= "false"  
  7. android:userVisible= "true" />

Parameter Description:

android:contentAuthority specifies that the ContentProvider to be synchronized has an android:authorities attribute in its AndroidManifest.xml file.

android:accountType indicates the type of account to be synchronized.

android:userVisible sets whether to display in "Settings"

android:supportsUploading Set whether notifyChange notification is required for synchronization

android:allowParallelSyncs Whether to support simultaneous synchronization of multiple accounts

android:isAlwaysSyncable Set isSyncable to 1 for all accounts

android:syncAdapterSettingsAction specifies an Action that can set the synchronized activity.

  • Account calls Sync service

First configure the Account (step 3), and then implement it through ContentProvider

Manual Update

  1. public void triggerRefresh() {
  2. Bundle b = new Bundle();
  3. b.putBoolean(ContentResolver.SYNC_EXTRAS_MANUAL, true );
  4. b.putBoolean(ContentResolver.SYNC_EXTRAS_EXPEDITED, true );
  5. ContentResolver.requestSync(
  6. account,
  7. CONTENT_AUTHORITY,
  8. b);
  9. }

Add Account

  1. Account account = AccountService.GetAccount();
  2. AccountManager accountManager = (AccountManager) context.getSystemService(Context.ACCOUNT_SERVICE);
  3. accountManager.addAccountExplicitly(...)

Synchronization cycle setting

  1. ContentResolver.setIsSyncable(account, CONTENT_AUTHORITY, 1);
  2. ContentResolver.setSyncAutomatically(account, CONTENT_AUTHORITY, true );
  3. ContentResolver.addPeriodicSync(account, CONTENT_AUTHORITY, new Bundle(), SYNC_FREQUENCY);

3. Establishing an Account System (Account Authenticator)

Synchronize by creating an Account and associating it with the SyncAdapter service

Continue

<<:  Essential for lazy people: multiple pull-down refresh, pull-up to load more, and configure custom header ad space library

>>:  A new method to improve the survival rate of Android application processes (Part 2)

Recommend

How much does it cost to rent a server with high-defense DDOS IP?

How much does it cost to rent a server with high-...

How to create a popular short video with high exposure

Tik Tok, the short video app that has exploded in...

Marketing Planning Triangle Law!

Predicting the launch of new products is like for...

Behind Kuaishou’s entry into cities, how to promote in the rural market?

The rural market gives you a long time, and you h...

【Operational Methodology】Strategies of Cold Start and High Growth

Note: The content comes from NetEase Cloud Classr...

Will humans be replaced by artificial intelligence? Machines cannot do this

Copyrighted images from the gallery, unauthorized...

BMW and IBM's Watson team up to develop driver assistance technology

Recently, IBM's Watson artificial intelligenc...

Android Permission Management Principles (including 6.0)

Preface Before MarshMallow, permissions were gran...

Watching seals, catching krill, eating sashimi, we live in Antarctica

Excerpted from: "Inside and Outside the Clas...

What? High heels were invented for men!

I believe that every girl had a wish when she was...

Two strategies for APP promotion: casting a wide net and focusing on fishing

There is no fancy opening remarks, I will simply ...