【Android 进程保活】应用进程拉活 ( 系统 Service 机制拉活 | Service 组件 onStartCommand 方法分析 | 源码资源 )
文章目录
一、 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_STICKY
return mStartCompatibility ? START_STICKY_COMPATIBILITY : START_STICKY;
}
/**
* @hide
*/
@UnsupportedAppUsage
public 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());
}
@UnsupportedAppUsage
private 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() {
}
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public 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" />
<application
android: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"
-->
<activity
android:name=".one_pixel_activity.OnePixelActivity"
android:excludeFromRecents="true"
android:taskAffinity="kim.hsl.keep_progress_alive.onepixel"
android:theme="@style/OnePixelActivityTheme" />
<!-- 用于提权的前台进程 -->
<service
android:name=".foreground_service.ForegroundService"
android:enabled="true"
android:exported="true" />
<!-- 用于提权的前台进程, 关闭通知操作 -->
<service
android:name=".foreground_service.CancelNotificationService"
android:enabled="true"
android:exported="true" />
<!-- 系统 Service 机制拉活 -->
<service
android: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 {
@Override
protected 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));
}
@Override
protected void onDestroy() {
super.onDestroy();
// 1. 取消注册广播接收者, 也可以不取消注册
//KeepProgressAliveManager.getmInstance().registerReceiver(this);
}
}
三、 测试效果
程序正常启动 , 运行正常 ,
查询 oom_adj 值 ,
, 前台进程 ;
在手机中手动杀掉进程 , 杀掉进程后 , 又重新启动了一个相同进程 , 进程号改变了 ;
( 测试时没有抓到两个进程同框的画面 , 只截取了下面一张图 )
拉起后是个后台进程 , 任务栈中看不到 ;
四、 系统 Service 机制拉活总结
系统 Service 机制拉活 , 不是 100% 有效 , 有一定成功几率 ;
有些机型 ROM , 拉活无效 ; 测试的 Google Pixel2 Android 10 可以拉活 ; 有相当大的一部分手机不支持该 Service 机制拉活 ;
( 是否支持 , 与系统有关 , 与手机厂商有关 )
每次杀掉 Service 所在应用进程 , 重启都比上一次慢 , 大约杀掉几次进程后 ( 5 次内 ) , 系统就不再拉起该应用 ;
五、 源码资源
源码资源 :
相关文章
- 基于chromium for android开发Android浏览器
- android okio使用方法,Android 开源框架 Okio 原理剖析「建议收藏」
- android declare-styleable 和style,Android 关于declare-styleable属性的写法….
- android telephony 原理解析与开发指南_Android逆向pdf
- android intent打开各种格式文档方法
- 【Android NDK 开发】JNI 线程 ( JNI 线程创建 | 线程执行函数 | 非 JNI 方法获取 JNIEnv 与 Java 对象 | 线程获取 JNIEnv | 全局变量设置 )
- 【Android 异步操作】Handler 机制 ( Android 提供的 Handler 源码解析 | Handler 构造与消息分发 | MessageQueue 消息队列相关方法 )
- 【IOC 控制反转】Android 事件依赖注入 ( 事件依赖注入具体的操作细节 | 获取 Activity 中的所有方法 | 获取方法上的注解 | 获取注解上的注解 | 通过注解属性获取事件信息 )
- 【错误记录】Android Studio 编译时 lint 检查报错 ( Error: Google Play requires that apps target API level 29 or )
- 【Android Gradle 插件】LintOptions 配置 ⑩ ( textReport 属性配置 | textOutput 属性配置 | warningsAsErrors 属性配置 )
- 【Android UI】Path 测量 PathMeasure ② ( PathMeasure API 简介 | nextContour 函数 | getPosTan 函数 ★ | 曲线切线处理 )
- Android清除本地数据缓存代码详解手机开发
- Android开发中遇到的问题(二)——新建android工程的时候eclipse没有生成MainActivity和layout布局详解手机开发
- Android欺诈僵尸网络Chamois的检测和清除
- Android工程内嵌资源文件的两种方法
- 基于将Android工程做成jar包和资源文件的解决方法
- android,不显示标题的方法小例子
- 解析Android资源文件及他们的读取方法详解
- Android开发笔记之:消息循环与Looper的详解
- android图库竖屏不显示statusbar的解决方法
- Android中应用界面主题Theme使用方法和页面定时跳转应用
- android获取照片的快照思路及实现方法
- Android中让图片自适应控件的大小的方法
- android杂记:C++文件的添加log方法分享
- android自定义TabActivity的实例方法
- Android判断屏幕是横屏或是竖屏的简单实现方法
- Android开发之注册登录方法示例