文章目录

  • 一、 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 方法分析 | 源码资源 )相关推荐

  1. 【Android 进程保活】提升进程优先级 ( 1 像素 Activity 提高进程优先级 | taskAffinity 亲和性说明 | 运行效果 | 源码资源 )

    文章目录 一.1 像素 Activity 提高进程优先级 1.主界面 MainActivity 2.1 像素 Activity 3.广播接收者 4.管理类 5.AndroidManifest.xml ...

  2. android 字符串中截取,【安卓按键精灵】几种字符串提取的方法(源码)

    截取法提取两个字符串之间的内容 TracePrint GetStrAB("如果想要写成一行代码,那么就可以用冒号连接","想要","代码") ...

  3. 【Android 进程保活】提升进程优先级 ( 使用前台 Service 提高应用进程优先级 | 效果展示 | 源码资源 )

    文章目录 一. 使用前台 Service 提高应用进程优先级 1. 前台 Service 代码 2. 前台 Service 代码 3. 启动服务 二.效果展示 三.源码资源 一. 使用前台 Servi ...

  4. 【Android 进程保活】应用进程拉活 ( 账户同步拉活 | 账号添加 | 源码资源 )

    文章目录 一. 账号添加 二. 代码示例 1. 账号添加工具类 2. 权限注册 3. 在 Activity 中调用上述工具类 4. 运行效果 三. 源码资源 一. 账号添加 在上一篇博客 [Andro ...

  5. 【Android 进程保活】应用进程拉活 ( 双进程守护保活 )

    文章目录 一. 双进程守护保活原理 二. 双进程守护保活完整源码 1.AIDL 接口 2.本地前台服务 Service 3.远程前台服务 Service 4.清单配置 5.启动两个服务 5.执行效果 ...

  6. 【Android 进程保活】应用进程拉活 ( 双进程守护 + JobScheduler 保活 | 成功率最高 | 推荐使用 )

    文章目录 一. 双进程守护保活 + JobScheduler 原理 二. 双进程守护保活 + JobScheduler 源码 1.JobService 代码 2.判定服务运行工具类 3.清单文件 4. ...

  7. 【Android 进程保活】应用进程拉活 ( JobScheduler 拉活 | JobScheduler 使用流程 | JobService 服务 | 不同版本兼容 | 源码资源 )

    文章目录 一. JobScheduler 用法简介 二. JobScheduler 拉活完整代码 1. JobService 2.清单文件 3.启动 JobScheduler 任务 4.运行效果 三. ...

  8. 【Android 进程保活】提升进程优先级 ( 使用前台 Service 提高应用进程优先级 | 启动相同 id 的第二个前台 Service 关闭通知 )

    文章目录 一. 前台 Service 通知问题 二. 设置 startForeground id 参数为 0 三. 启动相同 id 的第二个前台 Service 关闭通知 1. 前台服务 1 2. 关 ...

  9. Android 系统(265)----Android进程保活全攻略(上)

    Android进程保活全攻略(上) 对于每个公司的APP来说,当然都希望自己APP的进程尽量的不被杀死,于是乎,就有了一些列进程保活的方法出现,网上也有很多关于这类的文章,但网上很多资料往往只告诉了思 ...

最新文章

  1. android studio使用问题——instant run
  2. char值序列是什么Java_CharSequence和java之间的确切区别
  3. AS升级编译报错:The SourceSet 'instrumentTest' is not recognized by the Android Gradle Plugin....
  4. 操作系统 :银行家算法的实现(C++)
  5. ViewBag 找不到编译动态表达式所需的一种或多种类型,是否缺少引用?
  6. Java故障定位方法总结
  7. ATL接口映射宏详解
  8. 动态规划之马拉车算法(Python解法)
  9. C# 计算农历日期方法 2022
  10. (二)智能化技术如何赋能能源数字化转型及智慧化应用?
  11. OpenLayers多源数据加载一:数据组织
  12. 各双拼输入方案之间有明显的优劣之分吗?
  13. 123457123457#0#-----com.cym.shuXueWangGuo1--前拼后广--儿童数学
  14. Linux开关键盘背光灯
  15. 多边形颜色填充-X扫描线算法
  16. 教育邮箱申请office365激活失败处理
  17. Javascript 将阿拉伯数字转换成罗马数字
  18. Android中当item数量超过一定大小时,将RecyclerView高度固定
  19. 可以狭义的将计算机系统定义为,号外!号外!管理系列之《管理系统中计算机应用》...
  20. 【计量经济学导论】02. 多元回归模型

热门文章

  1. linux的引导流程
  2. Python爬虫(六)_Requests的使用
  3. Firebird日期时间操作
  4. Redis的安装部署
  5. 【bzoj4842】[Neerc2016]Delight for a Cat 线性规划与网络流
  6. 计划程序:拒绝重复工作,让效率翻倍!
  7. MYSQL-RJWEB 博客学习
  8. Cocoapods 第三方类库管理工具
  9. 探秘腾讯Android手机游戏平台之不安装游戏APK直接启动法
  10. 软件测试技术---黑盒测试