【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 方法分析 | 源码资源 )相关推荐
- 【Android 进程保活】提升进程优先级 ( 1 像素 Activity 提高进程优先级 | taskAffinity 亲和性说明 | 运行效果 | 源码资源 )
文章目录 一.1 像素 Activity 提高进程优先级 1.主界面 MainActivity 2.1 像素 Activity 3.广播接收者 4.管理类 5.AndroidManifest.xml ...
- android 字符串中截取,【安卓按键精灵】几种字符串提取的方法(源码)
截取法提取两个字符串之间的内容 TracePrint GetStrAB("如果想要写成一行代码,那么就可以用冒号连接","想要","代码") ...
- 【Android 进程保活】提升进程优先级 ( 使用前台 Service 提高应用进程优先级 | 效果展示 | 源码资源 )
文章目录 一. 使用前台 Service 提高应用进程优先级 1. 前台 Service 代码 2. 前台 Service 代码 3. 启动服务 二.效果展示 三.源码资源 一. 使用前台 Servi ...
- 【Android 进程保活】应用进程拉活 ( 账户同步拉活 | 账号添加 | 源码资源 )
文章目录 一. 账号添加 二. 代码示例 1. 账号添加工具类 2. 权限注册 3. 在 Activity 中调用上述工具类 4. 运行效果 三. 源码资源 一. 账号添加 在上一篇博客 [Andro ...
- 【Android 进程保活】应用进程拉活 ( 双进程守护保活 )
文章目录 一. 双进程守护保活原理 二. 双进程守护保活完整源码 1.AIDL 接口 2.本地前台服务 Service 3.远程前台服务 Service 4.清单配置 5.启动两个服务 5.执行效果 ...
- 【Android 进程保活】应用进程拉活 ( 双进程守护 + JobScheduler 保活 | 成功率最高 | 推荐使用 )
文章目录 一. 双进程守护保活 + JobScheduler 原理 二. 双进程守护保活 + JobScheduler 源码 1.JobService 代码 2.判定服务运行工具类 3.清单文件 4. ...
- 【Android 进程保活】应用进程拉活 ( JobScheduler 拉活 | JobScheduler 使用流程 | JobService 服务 | 不同版本兼容 | 源码资源 )
文章目录 一. JobScheduler 用法简介 二. JobScheduler 拉活完整代码 1. JobService 2.清单文件 3.启动 JobScheduler 任务 4.运行效果 三. ...
- 【Android 进程保活】提升进程优先级 ( 使用前台 Service 提高应用进程优先级 | 启动相同 id 的第二个前台 Service 关闭通知 )
文章目录 一. 前台 Service 通知问题 二. 设置 startForeground id 参数为 0 三. 启动相同 id 的第二个前台 Service 关闭通知 1. 前台服务 1 2. 关 ...
- Android 系统(265)----Android进程保活全攻略(上)
Android进程保活全攻略(上) 对于每个公司的APP来说,当然都希望自己APP的进程尽量的不被杀死,于是乎,就有了一些列进程保活的方法出现,网上也有很多关于这类的文章,但网上很多资料往往只告诉了思 ...
最新文章
- android studio使用问题——instant run
- char值序列是什么Java_CharSequence和java之间的确切区别
- AS升级编译报错:The SourceSet 'instrumentTest' is not recognized by the Android Gradle Plugin....
- 操作系统 :银行家算法的实现(C++)
- ViewBag 找不到编译动态表达式所需的一种或多种类型,是否缺少引用?
- Java故障定位方法总结
- ATL接口映射宏详解
- 动态规划之马拉车算法(Python解法)
- C# 计算农历日期方法 2022
- (二)智能化技术如何赋能能源数字化转型及智慧化应用?
- OpenLayers多源数据加载一:数据组织
- 各双拼输入方案之间有明显的优劣之分吗?
- 123457123457#0#-----com.cym.shuXueWangGuo1--前拼后广--儿童数学
- Linux开关键盘背光灯
- 多边形颜色填充-X扫描线算法
- 教育邮箱申请office365激活失败处理
- Javascript 将阿拉伯数字转换成罗马数字
- Android中当item数量超过一定大小时,将RecyclerView高度固定
- 可以狭义的将计算机系统定义为,号外!号外!管理系列之《管理系统中计算机应用》...
- 【计量经济学导论】02. 多元回归模型