【Android 进程保活】应用进程拉活 ( 双进程守护保活 )
韩曙亮
于 2021-04-11 21:50:46 发布
阅读量3.6k
收藏 19
点赞数 5
分类专栏: Android 性能优化 # Android 进程保活 文章标签: 进程保活 双进程守护保活
版权
Android 性能优化
同时被 2 个专栏收录
189 篇文章54 订阅
订阅专栏
Android 进程保活
15 篇文章14 订阅
订阅专栏
文章目录
一、 双进程守护保活原理
二、 双进程守护保活完整源码
1、AIDL 接口
2、本地前台服务 Service
3、远程前台服务 Service
4、清单配置
5、启动两个服务
5、执行效果
三、 源码资源
一、 双进程守护保活原理
双进程守护拉活 , 使用 JobScheduler 拉活 和 系统 Service 机制拉活 两种拉活方式 , 结合起来使用 ;
双进程机制拉活 , 比之前的 广播拉活 , 系统 Service 机制拉活 , 账户同步拉活 , JobScheduler 机制拉活 , 成功率都要高 , 可靠性比较高 , 但是也存在失败的情况 ;
JobScheduler 原理 :
在应用中 , 运行了一个主进程 , 除此之外 , 还运行了一个 " 本地前台进程 " , 运行该 " 本地前台进程 " 时 , 开启前台进程 , 用于提权 , 并绑定 " 远程前台进程 " ;
" 远程前台进程 " 与 " 本地前台进程 " 实现了相同的功能 , 代码基本一致 , 这两个进程都是前台进程 , 都进行了提权 , 并且互相绑定 , 当监听到绑定的另外一个进程突然断开连接 , 则本进程再次开启前台进程提权 , 并且重新绑定对方进程 , 以达到拉活对方进程的目的 ;
举例 : " 本地前台进程 " LocalForegroundService , " 远程前台进程 " RemoteForegroundService ;
这两个进程之间需要绑定 , 这里就需要定义 AIDL 接口 IMyAidlInterface , 每个服务中都需要定义继承 IMyAidlInterface.Stub 的 Binder 类 , 作为进程间通信的桥梁 ; ( 这是个默认的 AIDL 接口 )
/**
* AIDL 远程调用接口
* 其它进程调与该 RemoteForegroundService 服务进程通信时 , 可以通过 onBind 方法获取该 myBinder 成员
* 通过调用该成员的 basicTypes 方法 , 可以与该进程进行数据传递
*/
class MyBinder extends IMyAidlInterface.Stub {
@Override
public void basicTypes(
int anInt, long aLong, boolean aBoolean, float aFloat,
double aDouble, String aString) throws RemoteException {
// 通信内容
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
" 本地前台进程 " LocalForegroundService 在 onCreate 方法中开启前台服务 , 提权 , 参考 【Android 进程保活】提升进程优先级 ( 使用前台 Service 提高应用进程优先级 | 效果展示 | 源码资源 ) , 并且创建用于进程间通信的 Binder 对象 ;
/**
* 远程调用 Binder 对象
*/
private MyBinder myBinder;
@Override
public void onCreate() {
super.onCreate();
// 创建 Binder 对象
myBinder = new MyBinder();
// 启动前台进程
startService();
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
" 本地前台进程 " LocalForegroundService , 在 onBind 方法中返回 onCreate 方法中创建的 Binder 对象 ;
@Override
public IBinder onBind(Intent intent) {
return myBinder;
}
1
2
3
4
" 本地前台进程 " LocalForegroundService 中 , 绑定远程进程时 , 需要使用到 ServiceConnection 类 , 在服务绑定成功时回调 onServiceConnected , 服务断开时回调 onServiceDisconnected 方法 ; 这里就在 onServiceDisconnected 方法中再次对本服务进行提权 , 并且再次绑定 " 远程前台进程 " RemoteForegroundService ;
class Connection implements ServiceConnection {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
// 服务绑定成功时回调
}
@Override
public void onServiceDisconnected(ComponentName name) {
// 再次启动前台进程
startService();
// 绑定另外一个远程进程
bindService();
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
另外特别注意权限问题 , 需要在清单文件中配置 android.permission.FOREGROUND_SERVICE 权限 :
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
1
二、 双进程守护保活完整源码
1、AIDL 接口
这里的 AIDL 不实现任何操作 , 是系统默认生成的 AIDL 接口 , 只是用于单纯的绑定两个进程 , 监听进程的连接断开 ;
// IMyAidlInterface.aidl
package kim.hsl.two_process_alive;
// Declare any non-default types here with import statements
interface IMyAidlInterface {
/**
* Demonstrates some basic types that you can use as parameters
* and return values in AIDL.
*/
void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat,
double aDouble, String aString);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
2、本地前台服务 Service
package kim.hsl.two_process_alive;
import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.Service;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.graphics.Color;
import android.os.Build;
import android.os.IBinder;
import android.os.RemoteException;
import androidx.core.app.NotificationCompat;
import static androidx.core.app.NotificationCompat.PRIORITY_MIN;
/**
-
前台服务提权
*/
public class LocalForegroundService extends Service {/**
- 远程调用 Binder 对象
*/
private MyBinder myBinder;
/**
- 连接对象
*/
private Connection connection;
/**
- AIDL 远程调用接口
- 其它进程调与该 RemoteForegroundService 服务进程通信时 , 可以通过 onBind 方法获取该 myBinder 成员
- 通过调用该成员的 basicTypes 方法 , 可以与该进程进行数据传递
*/
class MyBinder extends IMyAidlInterface.Stub {
@Override
public void basicTypes(
int anInt, long aLong, boolean aBoolean, float aFloat,
double aDouble, String aString) throws RemoteException {
// 通信内容
}
}
@Override
public IBinder onBind(Intent intent) {
return myBinder;
}@Override
public void onCreate() {
super.onCreate();
// 创建 Binder 对象
myBinder = new MyBinder();// 启动前台进程 startService();
}
private void startService(){
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O){
// startForeground();// 创建通知通道 NotificationChannel channel = new NotificationChannel("service", "service", NotificationManager.IMPORTANCE_NONE); channel.setLightColor(Color.BLUE); channel.setLockscreenVisibility(Notification.VISIBILITY_PRIVATE); NotificationManager service = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); // 正式创建 service.createNotificationChannel(channel); NotificationCompat.Builder builder = new NotificationCompat.Builder(this, "service"); Notification notification = builder.setOngoing(true) .setSmallIcon(R.mipmap.ic_launcher) .setPriority(PRIORITY_MIN) .setCategory(Notification.CATEGORY_SERVICE) .build(); // 开启前台进程 , API 26 以上无法关闭通知栏 startForeground(10, notification); } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2){ startForeground(10, new Notification()); // API 18 ~ 25 以上的设备 , 启动相同 id 的前台服务 , 并关闭 , 可以关闭通知 startService(new Intent(this, CancelNotificationService.class)); } else if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR2){ // 将该服务转为前台服务 // 需要设置 ID 和 通知 // 设置 ID 为 0 , 就不显示已通知了 , 但是 oom_adj 值会变成后台进程 11 // 设置 ID 为 1 , 会在通知栏显示该前台服务 // 8.0 以上该用法报错 startForeground(10, new Notification()); }
}
/**
绑定 另外一个 服务
-
LocalForegroundService 与 RemoteForegroundService 两个服务互相绑定
*/
private void bindService(){
// 绑定 另外一个 服务
// LocalForegroundService 与 RemoteForegroundService 两个服务互相绑定// 创建连接对象
connection = new Connection();// 创建本地前台进程组件意图
Intent bindIntent = new Intent(this, RemoteForegroundService.class);
// 绑定进程操作
bindService(bindIntent, connection, BIND_AUTO_CREATE);
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
// 绑定另外一个服务
bindService();
return super.onStartCommand(intent, flags, startId);
}class Connection implements ServiceConnection {
@Override public void onServiceConnected(ComponentName name, IBinder service) { // 服务绑定成功时回调 } @Override public void onServiceDisconnected(ComponentName name) { // 再次启动前台进程 startService(); // 绑定另外一个远程进程 bindService(); }
}
/**
-
API 18 ~ 25 以上的设备, 关闭通知到专用服务
*/
public static class CancelNotificationService extends Service {
public CancelNotificationService() {
}@Override
public void onCreate() {
super.onCreate();
startForeground(10, new Notification());
stopSelf();
}@Override
public IBinder onBind(Intent intent) {
return null;
}
}
- 远程调用 Binder 对象
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
3、远程前台服务 Service
package kim.hsl.two_process_alive;
import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.Service;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.graphics.Color;
import android.os.Build;
import android.os.IBinder;
import android.os.RemoteException;
import androidx.core.app.NotificationCompat;
import static androidx.core.app.NotificationCompat.PRIORITY_MIN;
/**
-
前台服务提权
*/
public class RemoteForegroundService extends Service {/**
- 远程调用 Binder 对象
*/
private MyBinder myBinder;
/**
- 连接对象
*/
private Connection connection;
/**
- AIDL 远程调用接口
- 其它进程调与该 RemoteForegroundService 服务进程通信时 , 可以通过 onBind 方法获取该 myBinder 成员
- 通过调用该成员的 basicTypes 方法 , 可以与该进程进行数据传递
*/
class MyBinder extends IMyAidlInterface.Stub {
@Override
public void basicTypes(
int anInt, long aLong, boolean aBoolean, float aFloat,
double aDouble, String aString) throws RemoteException {
// 通信内容
}
}
@Override
public IBinder onBind(Intent intent) {
return myBinder;
}@Override
public void onCreate() {
super.onCreate();
// 创建 Binder 对象
myBinder = new MyBinder();// 启动前台进程 startService();
}
private void startService(){
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O){
// startForeground();// 创建通知通道 NotificationChannel channel = new NotificationChannel("service", "service", NotificationManager.IMPORTANCE_NONE); channel.setLightColor(Color.BLUE); channel.setLockscreenVisibility(Notification.VISIBILITY_PRIVATE); NotificationManager service = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); // 正式创建 service.createNotificationChannel(channel); NotificationCompat.Builder builder = new NotificationCompat.Builder(this, "service"); Notification notification = builder.setOngoing(true) .setSmallIcon(R.mipmap.ic_launcher) .setPriority(PRIORITY_MIN) .setCategory(Notification.CATEGORY_SERVICE) .build(); // 开启前台进程 , API 26 以上无法关闭通知栏 startForeground(10, notification); } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2){ startForeground(10, new Notification()); // API 18 ~ 25 以上的设备 , 启动相同 id 的前台服务 , 并关闭 , 可以关闭通知 startService(new Intent(this, CancelNotificationService.class)); } else if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR2){ // 将该服务转为前台服务 // 需要设置 ID 和 通知 // 设置 ID 为 0 , 就不显示已通知了 , 但是 oom_adj 值会变成后台进程 11 // 设置 ID 为 1 , 会在通知栏显示该前台服务 // 8.0 以上该用法报错 startForeground(10, new Notification()); }
}
/**
绑定 另外一个 服务
-
LocalForegroundService 与 RemoteForegroundService 两个服务互相绑定
*/
private void bindService(){
// 绑定 另外一个 服务
// LocalForegroundService 与 RemoteForegroundService 两个服务互相绑定// 创建连接对象
connection = new Connection();// 创建本地前台进程组件意图
Intent bindIntent = new Intent(this, LocalForegroundService.class);
// 绑定进程操作
bindService(bindIntent, connection, BIND_AUTO_CREATE);
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
// 绑定另外一个服务
bindService();
return super.onStartCommand(intent, flags, startId);
}class Connection implements ServiceConnection {
@Override public void onServiceConnected(ComponentName name, IBinder service) { // 服务绑定成功时回调 } @Override public void onServiceDisconnected(ComponentName name) { // 再次启动前台进程 startService(); // 绑定另外一个远程进程 bindService(); }
}
/**
-
API 18 ~ 25 以上的设备, 关闭通知到专用服务
*/
public static class CancelNotificationService extends Service {
public CancelNotificationService() {
}@Override
public void onCreate() {
super.onCreate();
startForeground(10, new Notification());
stopSelf();
}@Override
public IBinder onBind(Intent intent) {
return null;
}
}
} - 远程调用 Binder 对象
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
4、清单配置
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="kim.hsl.two_process_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.Two_Process_Alive">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<!-- 本地提权前台服务 Service -->
<service
android:name=".LocalForegroundService"
android:enabled="true"
android:exported="true"></service>
<!-- 本地服务 , API 18 ~ 25 以上的设备, 关闭通知到专用服务 -->
<service
android:name=".LocalForegroundService$CancelNotificationService"
android:enabled="true"
android:exported="true"></service>
<!-- 远程提权前台服务 Service -->
<service
android:name=".RemoteForegroundService"
android:enabled="true"
android:exported="true"
android:process=":remote"></service>
<!-- 远程服务 , API 18 ~ 25 以上的设备, 关闭通知到专用服务 -->
<service
android:name=".RemoteForegroundService$CancelNotificationService"
android:enabled="true"
android:exported="true"
android:process=":remote"></service>
</application>
</manifest>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
5、启动两个服务
package kim.hsl.two_process_alive;
import androidx.appcompat.app.AppCompatActivity;
import android.content.Intent;
import android.os.Bundle;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// 通过前台 Service 提升应用权限
// 启动普通 Service , 但是在该 Service 的 onCreate 方法中执行了 startForeground
// 变成了前台 Service 服务
startService(new Intent(this, LocalForegroundService.class));
startService(new Intent(this, RemoteForegroundService.class));
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
5、执行效果
执行上述应用后 , 可以看到启动了两个应用 , 干掉应用后 , 可以被远程进程拉起 , 干掉远程进程 , 远程进程可以本主进程服务拉起 ;
三、 源码资源
源码资源 :
GitHub 地址 : https://github.com/han1202012/Two_Progress_Alive
CSDN 源码快照 : https://download.csdn.net/download/han1202012/16623056
————————————————
版权声明:本文为CSDN博主「韩曙亮」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/shulianghan/article/details/115604667