[[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 - // Adjustment used in certain places where we don't know it yet.
- // (Generally this is something that is going to be cached, but we
- // don't know the exact value in the cached range to assign yet.)
- static final int UNKNOWN_ADJ = 16;
-
- // This is a process only hosting activities that are not visible,
- // so it can be killed without any disruption.
- static final int CACHED_APP_MAX_ADJ = 15;
- static final int CACHED_APP_MIN_ADJ = 9;
-
- // The B list of SERVICE_ADJ
- // services that aren't as shiny and interesting as the ones in the A list.
- static final int SERVICE_B_ADJ = 8;
-
- // This is the process of the previous application that the user was in .
- // This process is kept above other things, because it is very common to
- // switch back to the previous app. This is important both for recent
- // task switch (toggling between the two top recent apps) as well as normal
- // UI flow such as clicking on a URI in the e-mail app to view in the browser,
- // and then pressing back to return to e-mail.
- static final int PREVIOUS_APP_ADJ = 7;
-
- // This is a process holding the home application
- // avoid killing it, even if it would normally be in the background,
- // because the user interacts with it so much.
- static final int HOME_APP_ADJ = 6;
-
- // This is a process holding an application service
- // have much of an impact as far as the user is concerned.
- static final int SERVICE_ADJ = 5;
-
- // This is a process with a heavy-weight application. It is in the
- // background, but we want to try to avoid killing it. Value set in
- // system/rootdir/init.rc on startup.
- static final int HEAVY_WEIGHT_APP_ADJ = 4;
-
- // This is a process currently hosting a backup operation. Killing it
- // is not entirely fatal but is generally a bad idea.
- static final int BACKUP_APP_ADJ = 3;
-
- // This is a process only hosting components that are perceptible to the
- // user , and we really want to avoid killing them, but they are not
- // immediately visible. An example is background music playback.
- static final int PERCEPTIBLE_APP_ADJ = 2;
-
- // This is a process only hosting activities that are visible to the
- // user , so we 'd prefer they don' t disappear.
- static final int VISIBLE_APP_ADJ = 1;
-
- // This is the process running the current foreground app. We'd really
- // rather not kill it!
- static final int FOREGROUND_APP_ADJ = 0;
-
- // This is a process that the system or a persistent process has bound to ,
- // and indicated it is important.
- static final int PERSISTENT_SERVICE_ADJ = -11;
-
- // This is a system persistent process, such as telephony. Definitely
- // don't want to kill it, but doing so is not completely fatal.
- static final int PERSISTENT_PROC_ADJ = -12;
-
- // The system process runs at the default adjustment.
- static final int SYSTEM_ADJ = -16;
-
- // Special code for native processes that are not being managed by the system (so
- // don't have an oom adj assigned by the system).
- 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 - static uint32_t lowmem_debug_level = 1;
- static int lowmem_adj[6] = {
- 0,
- 1,
- 6,
- 12,
- };
- static int lowmem_adj_size = 4;
- static int lowmem_minfree[6] = {
- 3 * 512, /* 6MB */
- 2 * 1024, /* 8MB */
- 4 * 1024, /* 16MB */
- 16 * 1024, /* 64MB */
- };
- 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 - # Set init and its forked children's oom_adj.
- 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) - adb shell
- ps | grep process name
- 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
- @Override
- public int onStartCommand(Intent intent, int flags, int startId) {
- startForeground(R.id.notify, new Notification());
- startService(new Intent(this, FakeService.class));
- return super.onStartCommand(intent, flags, startId);
- }
- FakeService temporary service
- public class FakeService extends Service {
- @Nullable
- @Override
- public IBinder onBind(Intent intent) {
- return null ;
- }
-
- @Override
- public int onStartCommand(Intent intent, int flags, int startId) {
- startForeground(R.id.notify, new Notification());
- stopSelf();
- return super.onStartCommand(intent, flags, startId);
- }
-
- @Override
- public void onDestroy() {
- stopForeground( true );
- super.onDestroy();
- }
- }
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. - public class XXAccountProvider extends ContentProvider {
- public static final String AUTHORITY = "Package name.provider" ;
- public static final String CONTENT_URI_BASE = "content://" + AUTHORITY;
- public static final String TABLE_NAME = "data" ;
- public static final Uri CONTENT_URI = Uri.parse(CONTENT_URI_BASE + "/" + TABLE_NAME);
-
- @Override
- public boolean onCreate() {
- return true ;
- }
-
- @Nullable
- @Override
- public Cursor query(Uri uri, String[] projection, String selection,
- String[] selectionArgs, String sortOrder) {
- return null ;
- }
-
- @Nullable
- @Override
- public String getType(Uri uri) {
- return new String();
- }
-
- @Nullable
- @Override
- public Uri insert (Uri uri, ContentValues values ) {
- return null ;
- }
-
- @Override
- public int delete (Uri uri, String selection, String[] selectionArgs) {
- return 0;
- }
-
- @Override
- public int update (Uri uri, ContentValues values , String selection, String[] selectionArgs) {
- return 0;
- }
- }
Then declare it in the Manifest - <provider
- android: name = "**.XXAccountProvider"
- android:authorities= "@string/account_auth_provider"
- android:exported= "false"
- 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: - public class XXSyncService extends Service {
- private static final Object sSyncAdapterLock = new Object();
- private static XXSyncAdapter sSyncAdapter = null ;
- @Override
- public void onCreate() {
- synchronized (sSyncAdapterLock) {
- if (sSyncAdapter == null ) {
- sSyncAdapter = new XXSyncAdapter(getApplicationContext(), true );
- }
- }
- }
-
- @Override
- public IBinder onBind(Intent intent) {
- return sSyncAdapter.getSyncAdapterBinder();
- }
-
- static class XXSyncAdapter extends AbstractThreadedSyncAdapter {
- public XXSyncAdapter(Context context, boolean autoInitialize) {
- super(context, autoInitialize);
- }
- @Override
- public void onPerformSync(Account account, Bundle extras, String authority, ContentProviderClient provider, SyncResult syncResult) {
- getContext().getContentResolver().notifyChange(XXAccountProvider.CONTENT_URI, null , false );
- }
- }
- }
- <service
- android: name = "**.XXSyncService"
- android:exported= "true"
- android:process= ":core" >
- <intent-filter>
- < action
- android: name = "android.content.SyncAdapter" />
- </intent-filter>
- <meta-data
- android: name = "android.content.SyncAdapter"
- android:resource= "@xml/sync_adapter" />
- </service>
Where sync_adapter is: - <sync-adapter xmlns:android= "http://schemas.android.com/apk/res/android"
- android:accountType= "@string/account_auth_type"
- android:allowParallelSyncs= "false"
- android:contentAuthority= "@string/account_auth_provide"
- android:isAlwaysSyncable= "true"
- android:supportsUploading= "false"
- 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 - public void triggerRefresh() {
- Bundle b = new Bundle();
- b.putBoolean(ContentResolver.SYNC_EXTRAS_MANUAL, true );
- b.putBoolean(ContentResolver.SYNC_EXTRAS_EXPEDITED, true );
- ContentResolver.requestSync(
- account,
- CONTENT_AUTHORITY,
- b);
- }
Add Account - Account account = AccountService.GetAccount();
- AccountManager accountManager = (AccountManager) context.getSystemService(Context.ACCOUNT_SERVICE);
- accountManager.addAccountExplicitly(...)
Synchronization cycle setting - ContentResolver.setIsSyncable(account, CONTENT_AUTHORITY, 1);
- ContentResolver.setSyncAutomatically(account, CONTENT_AUTHORITY, true );
- 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 |