【Android 进程保活】应用进程拉活 ( 系统 Service 机制拉活 | Service 组件 onStartCommand 方法分析 | 源码资源 )
文章目錄
- 一、 Service 組件 onStartCommand 方法分析
- 1、 onStartCommand 函數返回值分析
- 2、 onStartCommand 函數 START_STICKY_COMPATIBILITY 返回值
- 3、 onStartCommand 函數 START_STICKY 返回值
- 4、 onStartCommand 函數 START_NOT_STICKY 返回值
- 5、 onStartCommand 函數 START_REDELIVER_INTENT 返回值
- 二、 系統 Service 機制拉活
- 1、 Service 代碼
- 2、 清單配置
- 3、啟動服務
- 三、 測試效果
- 四、 系統 Service 機制拉活總結
- 五、 源碼資源
一、 Service 組件 onStartCommand 方法分析
1、 onStartCommand 函數返回值分析
Service 的生命周期函數 onStartCommand 方法 , 返回一個整型值 ;
Service 中的 mStartCompatibility 標記默認是 false , 因此 onStartCommand 函數默認返回的整型值是 Service.START_STICKY 值 ;
mStartCompatibility 值在 Service 中的 attach 方法中賦值 , 其值為 getApplicationInfo().targetSdkVersion < Build.VERSION_CODES.ECLAIR , 即手機的 API Level 版本號是否小于 5 , 現在肯定沒有版本號小于 5 的手機 , 該值默認是 false ;
public abstract class Service extends ContextWrapper implements ComponentCallbacks2,ContentCaptureManager.ContentCaptureClient {/*** Called by the system every time a client explicitly starts the service by calling * {@link android.content.Context#startService}, providing the arguments it supplied and a * unique integer token representing the start request. Do not call this method directly.* * <p>For backwards compatibility, the default implementation calls* {@link #onStart} and returns either {@link #START_STICKY}* or {@link #START_STICKY_COMPATIBILITY}.* * <p class="caution">Note that the system calls this on your* service's main thread. A service's main thread is the same* thread where UI operations take place for Activities running in the* same process. You should always avoid stalling the main* thread's event loop. When doing long-running operations,* network calls, or heavy disk I/O, you should kick off a new* thread, or use {@link android.os.AsyncTask}.</p>** @param intent The Intent supplied to {@link android.content.Context#startService}, * as given. This may be null if the service is being restarted after* its process has gone away, and it had previously returned anything* except {@link #START_STICKY_COMPATIBILITY}.* @param flags Additional data about this start request.* @param startId A unique integer representing this specific request to * start. Use with {@link #stopSelfResult(int)}.* * @return The return value indicates what semantics the system should* use for the service's current started state. It may be one of the* constants associated with the {@link #START_CONTINUATION_MASK} bits.* * @see #stopSelfResult(int)*/public @StartResult int onStartCommand(Intent intent, @StartArgFlags int flags, int startId) {onStart(intent, startId);// mStartCompatibility 標記默認是 false , 因此其返回值默認是 START_STICKYreturn mStartCompatibility ? START_STICKY_COMPATIBILITY : START_STICKY;}/*** @hide*/@UnsupportedAppUsagepublic final void attach(Context context,ActivityThread thread, String className, IBinder token,Application application, Object activityManager) {attachBaseContext(context);mThread = thread; // NOTE: unused - remove?mClassName = className;mToken = token;mApplication = application;mActivityManager = (IActivityManager)activityManager;mStartCompatibility = getApplicationInfo().targetSdkVersion< Build.VERSION_CODES.ECLAIR;setContentCaptureOptions(application.getContentCaptureOptions());}@UnsupportedAppUsageprivate boolean mStartCompatibility = false;onStartCommand 的返回值有以下幾種情況 :
- Service.START_STICKY_COMPATIBILITY
- Service.START_STICKY
- Service.START_NOT_STICKY
- Service.START_REDELIVER_INTENT
2、 onStartCommand 函數 START_STICKY_COMPATIBILITY 返回值
Service.START_STICKY_COMPATIBILITY : START_STICKY 兼容版本 , onStartCommand 方法返回該返回值時 , 不能保證服務可以重啟 ;
/*** Constant to return from {@link #onStartCommand}: compatibility* version of {@link #START_STICKY} that does not guarantee that* {@link #onStartCommand} will be called again after being killed.*/public static final int START_STICKY_COMPATIBILITY = 0;3、 onStartCommand 函數 START_STICKY 返回值
Service.START_STICKY : onStartCommand 方法返回該 START_STICKY 返回值時 , 如果在執行 onStartCommand 后 , 如果 Service 服務進程被殺掉 , 系統會保留 Service 狀態 , 但是不保留啟動服務的 Intent ; 之后系統會嘗試重新創建該 Service 服務 ; ( 更詳細的信息查看下方的源碼注釋 )
/*** Constant to return from {@link #onStartCommand}: if this service's* process is killed while it is started (after returning from* {@link #onStartCommand}), then leave it in the started state but* don't retain this delivered intent. Later the system will try to* re-create the service. Because it is in the started state, it will* guarantee to call {@link #onStartCommand} after creating the new* service instance; if there are not any pending start commands to be* delivered to the service, it will be called with a null intent* object, so you must take care to check for this.* * <p>This mode makes sense for things that will be explicitly started* and stopped to run for arbitrary periods of time, such as a service* performing background music playback.*/public static final int START_STICKY = 1;4、 onStartCommand 函數 START_NOT_STICKY 返回值
Service.START_NOT_STICKY : " 非粘性 " , onStartCommand 方法返回該返回值時 , 如果在執行 onStartCommand 后 , 服務被殺死 , 系統不會重啟 Service 服務 ;
/*** Constant to return from {@link #onStartCommand}: if this service's* process is killed while it is started (after returning from* {@link #onStartCommand}), and there are no new start intents to* deliver to it, then take the service out of the started state and* don't recreate until a future explicit call to* {@link Context#startService Context.startService(Intent)}. The* service will not receive a {@link #onStartCommand(Intent, int, int)}* call with a null Intent because it will not be restarted if there* are no pending Intents to deliver.* * <p>This mode makes sense for things that want to do some work as a* result of being started, but can be stopped when under memory pressure* and will explicit start themselves again later to do more work. An* example of such a service would be one that polls for data from* a server: it could schedule an alarm to poll every N minutes by having* the alarm start its service. When its {@link #onStartCommand} is* called from the alarm, it schedules a new alarm for N minutes later,* and spawns a thread to do its networking. If its process is killed* while doing that check, the service will not be restarted until the* alarm goes off.*/public static final int START_NOT_STICKY = 2;5、 onStartCommand 函數 START_REDELIVER_INTENT 返回值
Service.START_REDELIVER_INTENT : 重傳 Intent ; onStartCommand 方法返回該返回值時 , 如果在執行 onStartCommand 后 , 服務被殺死 , 系統會自動重啟 , 并傳入 Intent 值 , 不會傳入 null ;
/*** Constant to return from {@link #onStartCommand}: if this service's* process is killed while it is started (after returning from* {@link #onStartCommand}), then it will be scheduled for a restart* and the last delivered Intent re-delivered to it again via* {@link #onStartCommand}. This Intent will remain scheduled for* redelivery until the service calls {@link #stopSelf(int)} with the* start ID provided to {@link #onStartCommand}. The* service will not receive a {@link #onStartCommand(Intent, int, int)}* call with a null Intent because it will only be restarted if* it is not finished processing all Intents sent to it (and any such* pending events will be delivered at the point of restart).*/public static final int START_REDELIVER_INTENT = 3;二、 系統 Service 機制拉活
根據上述 onStartCommand 方法返回值分析 , 只要返回值是 START_STICKY , 那么被殺掉的應用就會被重新拉起 ;
1、 Service 代碼
package kim.hsl.keep_progress_alive.stick_service;import android.app.Service; import android.content.Intent; import android.os.IBinder;public class StickService extends Service {public StickService() {}@Overridepublic IBinder onBind(Intent intent) {return null;}@Overridepublic int onStartCommand(Intent intent, int flags, int startId) {return super.onStartCommand(intent, flags, startId);} }
2、 清單配置
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android"package="kim.hsl.keep_progress_alive"><uses-permission android:name="android.permission.FOREGROUND_SERVICE" /><applicationandroid:allowBackup="true"android:icon="@mipmap/ic_launcher"android:label="@string/app_name"android:roundIcon="@mipmap/ic_launcher_round"android:supportsRtl="true"android:theme="@style/Theme.Keep_Progress_Alive"><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:excludeFromRecents="true"設置 Activity 親和性讓該界面在一個獨立的任務棧中 , 不要與本應用的其它任務棧放在一起避免解除鎖屏后 , 關閉 1 像素界面 , 將整個任務棧都喚醒android:taskAffinity="kim.hsl.keep_progress_alive.alive"--><activityandroid:name=".one_pixel_activity.OnePixelActivity"android:excludeFromRecents="true"android:taskAffinity="kim.hsl.keep_progress_alive.onepixel"android:theme="@style/OnePixelActivityTheme" /><!-- 用于提權的前臺進程 --><serviceandroid:name=".foreground_service.ForegroundService"android:enabled="true"android:exported="true" /><!-- 用于提權的前臺進程, 關閉通知操作 --><serviceandroid:name=".foreground_service.CancelNotificationService"android:enabled="true"android:exported="true" /><!-- 系統 Service 機制拉活 --><serviceandroid:name=".stick_service.StickService"android:enabled="true"android:exported="true" /></application></manifest>
3、啟動服務
package kim.hsl.keep_progress_alive;import androidx.appcompat.app.AppCompatActivity;import android.content.Intent; import android.os.Bundle;import kim.hsl.keep_progress_alive.foreground_service.ForegroundService; import kim.hsl.keep_progress_alive.one_pixel_activity.KeepProgressAliveManager; import kim.hsl.keep_progress_alive.stick_service.StickService;public class MainActivity extends AppCompatActivity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);// 1. 1 像素 Activity 提升應用權限// 注冊廣播接收者 , 1 像素 Activity 啟動的 廣播接收者//KeepProgressAliveManager.getmInstance().registerReceiver(this);// 2. 通過前臺 Service 提升應用權限// 啟動普通 Service , 但是在該 Service 的 onCreate 方法中執行了 startForeground// 變成了前臺 Service 服務//startService(new Intent(this, ForegroundService.class));// 3. 使用 Service 機制拉活startService(new Intent(this, StickService.class));}@Overrideprotected void onDestroy() {super.onDestroy();// 1. 取消注冊廣播接收者, 也可以不取消注冊//KeepProgressAliveManager.getmInstance().registerReceiver(this);} }
三、 測試效果
程序正常啟動 , 運行正常 ,
查詢 oom_adj 值 , 000 , 前臺進程 ;
在手機中手動殺掉進程 , 殺掉進程后 , 又重新啟動了一個相同進程 , 進程號改變了 ;
( 測試時沒有抓到兩個進程同框的畫面 , 只截取了下面一張圖 )
拉起后是個后臺進程 , 任務棧中看不到 ;
四、 系統 Service 機制拉活總結
系統 Service 機制拉活 , 不是 100%100\%100% 有效 , 有一定成功幾率 ;
有些機型 ROM , 拉活無效 ; 測試的 Google Pixel2 Android 10 可以拉活 ; 有相當大的一部分手機不支持該 Service 機制拉活 ;
( 是否支持 , 與系統有關 , 與手機廠商有關 )
每次殺掉 Service 所在應用進程 , 重啟都比上一次慢 , 大約殺掉幾次進程后 ( 555 次內 ) , 系統就不再拉起該應用 ;
五、 源碼資源
源碼資源 :
- GitHub 地址 : https://github.com/han1202012/Keep_Progress_Alive
- CSDN 源碼快照 : https://download.csdn.net/download/han1202012/16595429
總結
以上是生活随笔為你收集整理的【Android 进程保活】应用进程拉活 ( 系统 Service 机制拉活 | Service 组件 onStartCommand 方法分析 | 源码资源 )的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【错误记录】BLE 蓝牙搜索失效 ( 关
- 下一篇: 【Android 进程保活】应用进程拉活