【Android 進程?;睢繎?yīng)用進程拉活 ( 雙進程守護?;?)
韓曙亮
于 2021-04-11 21:50:46 發(fā)布
閱讀量3.6k
收藏 19
點贊數(shù) 5
分類專欄: Android 性能優(yōu)化 # Android 進程?;?文章標(biāo)簽: 進程?;?雙進程守護?;?br>
版權(quán)
Android 性能優(yōu)化
同時被 2 個專欄收錄
189 篇文章54 訂閱
訂閱專欄
Android 進程?;?br>
15 篇文章14 訂閱
訂閱專欄
文章目錄
一、 雙進程守護保活原理
二、 雙進程守護?;钔暾创a
1、AIDL 接口
2、本地前臺服務(wù) Service
3、遠(yuǎn)程前臺服務(wù) Service
4、清單配置
5、啟動兩個服務(wù)
5、執(zhí)行效果
三、 源碼資源
一、 雙進程守護保活原理
雙進程守護拉活 , 使用 JobScheduler 拉活 和 系統(tǒng) Service 機制拉活 兩種拉活方式 , 結(jié)合起來使用 ;
雙進程機制拉活 , 比之前的 廣播拉活 , 系統(tǒng) Service 機制拉活 , 賬戶同步拉活 , JobScheduler 機制拉活 , 成功率都要高 , 可靠性比較高 , 但是也存在失敗的情況 ;
JobScheduler 原理 :
在應(yīng)用中 , 運行了一個主進程 , 除此之外 , 還運行了一個 " 本地前臺進程 " , 運行該 " 本地前臺進程 " 時 , 開啟前臺進程 , 用于提權(quán) , 并綁定 " 遠(yuǎn)程前臺進程 " ;
" 遠(yuǎn)程前臺進程 " 與 " 本地前臺進程 " 實現(xiàn)了相同的功能 , 代碼基本一致 , 這兩個進程都是前臺進程 , 都進行了提權(quán) , 并且互相綁定 , 當(dāng)監(jiān)聽到綁定的另外一個進程突然斷開連接 , 則本進程再次開啟前臺進程提權(quán) , 并且重新綁定對方進程 , 以達(dá)到拉活對方進程的目的 ;
舉例 : " 本地前臺進程 " LocalForegroundService , " 遠(yuǎn)程前臺進程 " RemoteForegroundService ;
這兩個進程之間需要綁定 , 這里就需要定義 AIDL 接口 IMyAidlInterface , 每個服務(wù)中都需要定義繼承 IMyAidlInterface.Stub 的 Binder 類 , 作為進程間通信的橋梁 ; ( 這是個默認(rèn)的 AIDL 接口 )
/**
* AIDL 遠(yuǎn)程調(diào)用接口
* 其它進程調(diào)與該 RemoteForegroundService 服務(wù)進程通信時 , 可以通過 onBind 方法獲取該 myBinder 成員
* 通過調(diào)用該成員的 basicTypes 方法 , 可以與該進程進行數(shù)據(jù)傳遞
*/
class MyBinder extends IMyAidlInterface.Stub {
@Override
public void basicTypes(
int anInt, long aLong, boolean aBoolean, float aFloat,
double aDouble, String aString) throws RemoteException {
// 通信內(nèi)容
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
" 本地前臺進程 " LocalForegroundService 在 onCreate 方法中開啟前臺服務(wù) , 提權(quán) , 參考 【Android 進程?;睢刻嵘M程優(yōu)先級 ( 使用前臺 Service 提高應(yīng)用進程優(yōu)先級 | 效果展示 | 源碼資源 ) , 并且創(chuàng)建用于進程間通信的 Binder 對象 ;
/**
* 遠(yuǎn)程調(diào)用 Binder 對象
*/
private MyBinder myBinder;
@Override
public void onCreate() {
super.onCreate();
// 創(chuàng)建 Binder 對象
myBinder = new MyBinder();
// 啟動前臺進程
startService();
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
" 本地前臺進程 " LocalForegroundService , 在 onBind 方法中返回 onCreate 方法中創(chuàng)建的 Binder 對象 ;
@Override
public IBinder onBind(Intent intent) {
return myBinder;
}
1
2
3
4
" 本地前臺進程 " LocalForegroundService 中 , 綁定遠(yuǎn)程進程時 , 需要使用到 ServiceConnection 類 , 在服務(wù)綁定成功時回調(diào) onServiceConnected , 服務(wù)斷開時回調(diào) onServiceDisconnected 方法 ; 這里就在 onServiceDisconnected 方法中再次對本服務(wù)進行提權(quán) , 并且再次綁定 " 遠(yuǎn)程前臺進程 " RemoteForegroundService ;
class Connection implements ServiceConnection {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
// 服務(wù)綁定成功時回調(diào)
}
@Override
public void onServiceDisconnected(ComponentName name) {
// 再次啟動前臺進程
startService();
// 綁定另外一個遠(yuǎn)程進程
bindService();
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
另外特別注意權(quán)限問題 , 需要在清單文件中配置 android.permission.FOREGROUND_SERVICE 權(quán)限 :
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
1
二、 雙進程守護?;钔暾创a
1、AIDL 接口
這里的 AIDL 不實現(xiàn)任何操作 , 是系統(tǒng)默認(rèn)生成的 AIDL 接口 , 只是用于單純的綁定兩個進程 , 監(jiān)聽進程的連接斷開 ;
// 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、本地前臺服務(wù) 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;
/**
-
前臺服務(wù)提權(quán)
*/
public class LocalForegroundService extends Service {/**
- 遠(yuǎn)程調(diào)用 Binder 對象
*/
private MyBinder myBinder;
/**
- 連接對象
*/
private Connection connection;
/**
- AIDL 遠(yuǎn)程調(diào)用接口
- 其它進程調(diào)與該 RemoteForegroundService 服務(wù)進程通信時 , 可以通過 onBind 方法獲取該 myBinder 成員
- 通過調(diào)用該成員的 basicTypes 方法 , 可以與該進程進行數(shù)據(jù)傳遞
*/
class MyBinder extends IMyAidlInterface.Stub {
@Override
public void basicTypes(
int anInt, long aLong, boolean aBoolean, float aFloat,
double aDouble, String aString) throws RemoteException {
// 通信內(nèi)容
}
}
@Override
public IBinder onBind(Intent intent) {
return myBinder;
}@Override
public void onCreate() {
super.onCreate();
// 創(chuàng)建 Binder 對象
myBinder = new MyBinder();// 啟動前臺進程 startService();}
private void startService(){
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O){
// startForeground();// 創(chuàng)建通知通道 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); // 正式創(chuàng)建 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 以上無法關(guān)閉通知欄 startForeground(10, notification); } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2){ startForeground(10, new Notification()); // API 18 ~ 25 以上的設(shè)備 , 啟動相同 id 的前臺服務(wù) , 并關(guān)閉 , 可以關(guān)閉通知 startService(new Intent(this, CancelNotificationService.class)); } else if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR2){ // 將該服務(wù)轉(zhuǎn)為前臺服務(wù) // 需要設(shè)置 ID 和 通知 // 設(shè)置 ID 為 0 , 就不顯示已通知了 , 但是 oom_adj 值會變成后臺進程 11 // 設(shè)置 ID 為 1 , 會在通知欄顯示該前臺服務(wù) // 8.0 以上該用法報錯 startForeground(10, new Notification()); }}
/**
綁定 另外一個 服務(wù)
-
LocalForegroundService 與 RemoteForegroundService 兩個服務(wù)互相綁定
*/
private void bindService(){
// 綁定 另外一個 服務(wù)
// LocalForegroundService 與 RemoteForegroundService 兩個服務(wù)互相綁定// 創(chuàng)建連接對象
connection = new Connection();// 創(chuàng)建本地前臺進程組件意圖
Intent bindIntent = new Intent(this, RemoteForegroundService.class);
// 綁定進程操作
bindService(bindIntent, connection, BIND_AUTO_CREATE);
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
// 綁定另外一個服務(wù)
bindService();
return super.onStartCommand(intent, flags, startId);
}class Connection implements ServiceConnection {
@Override public void onServiceConnected(ComponentName name, IBinder service) { // 服務(wù)綁定成功時回調(diào) } @Override public void onServiceDisconnected(ComponentName name) { // 再次啟動前臺進程 startService(); // 綁定另外一個遠(yuǎn)程進程 bindService(); }}
/**
-
API 18 ~ 25 以上的設(shè)備, 關(guān)閉通知到專用服務(wù)
*/
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;
}
}
- 遠(yuǎn)程調(diào)用 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、遠(yuǎn)程前臺服務(wù) 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;
/**
-
前臺服務(wù)提權(quán)
*/
public class RemoteForegroundService extends Service {/**
- 遠(yuǎn)程調(diào)用 Binder 對象
*/
private MyBinder myBinder;
/**
- 連接對象
*/
private Connection connection;
/**
- AIDL 遠(yuǎn)程調(diào)用接口
- 其它進程調(diào)與該 RemoteForegroundService 服務(wù)進程通信時 , 可以通過 onBind 方法獲取該 myBinder 成員
- 通過調(diào)用該成員的 basicTypes 方法 , 可以與該進程進行數(shù)據(jù)傳遞
*/
class MyBinder extends IMyAidlInterface.Stub {
@Override
public void basicTypes(
int anInt, long aLong, boolean aBoolean, float aFloat,
double aDouble, String aString) throws RemoteException {
// 通信內(nèi)容
}
}
@Override
public IBinder onBind(Intent intent) {
return myBinder;
}@Override
public void onCreate() {
super.onCreate();
// 創(chuàng)建 Binder 對象
myBinder = new MyBinder();// 啟動前臺進程 startService();}
private void startService(){
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O){
// startForeground();// 創(chuàng)建通知通道 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); // 正式創(chuàng)建 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 以上無法關(guān)閉通知欄 startForeground(10, notification); } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2){ startForeground(10, new Notification()); // API 18 ~ 25 以上的設(shè)備 , 啟動相同 id 的前臺服務(wù) , 并關(guān)閉 , 可以關(guān)閉通知 startService(new Intent(this, CancelNotificationService.class)); } else if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR2){ // 將該服務(wù)轉(zhuǎn)為前臺服務(wù) // 需要設(shè)置 ID 和 通知 // 設(shè)置 ID 為 0 , 就不顯示已通知了 , 但是 oom_adj 值會變成后臺進程 11 // 設(shè)置 ID 為 1 , 會在通知欄顯示該前臺服務(wù) // 8.0 以上該用法報錯 startForeground(10, new Notification()); }}
/**
綁定 另外一個 服務(wù)
-
LocalForegroundService 與 RemoteForegroundService 兩個服務(wù)互相綁定
*/
private void bindService(){
// 綁定 另外一個 服務(wù)
// LocalForegroundService 與 RemoteForegroundService 兩個服務(wù)互相綁定// 創(chuàng)建連接對象
connection = new Connection();// 創(chuàng)建本地前臺進程組件意圖
Intent bindIntent = new Intent(this, LocalForegroundService.class);
// 綁定進程操作
bindService(bindIntent, connection, BIND_AUTO_CREATE);
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
// 綁定另外一個服務(wù)
bindService();
return super.onStartCommand(intent, flags, startId);
}class Connection implements ServiceConnection {
@Override public void onServiceConnected(ComponentName name, IBinder service) { // 服務(wù)綁定成功時回調(diào) } @Override public void onServiceDisconnected(ComponentName name) { // 再次啟動前臺進程 startService(); // 綁定另外一個遠(yuǎn)程進程 bindService(); }}
/**
-
API 18 ~ 25 以上的設(shè)備, 關(guān)閉通知到專用服務(wù)
*/
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;
}
}
} - 遠(yuǎn)程調(diào)用 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>
<!-- 本地提權(quán)前臺服務(wù) Service -->
<service
android:name=".LocalForegroundService"
android:enabled="true"
android:exported="true"></service>
<!-- 本地服務(wù) , API 18 ~ 25 以上的設(shè)備, 關(guān)閉通知到專用服務(wù) -->
<service
android:name=".LocalForegroundService$CancelNotificationService"
android:enabled="true"
android:exported="true"></service>
<!-- 遠(yuǎn)程提權(quán)前臺服務(wù) Service -->
<service
android:name=".RemoteForegroundService"
android:enabled="true"
android:exported="true"
android:process=":remote"></service>
<!-- 遠(yuǎn)程服務(wù) , API 18 ~ 25 以上的設(shè)備, 關(guān)閉通知到專用服務(wù) -->
<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、啟動兩個服務(wù)
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 提升應(yīng)用權(quán)限
// 啟動普通 Service , 但是在該 Service 的 onCreate 方法中執(zhí)行了 startForeground
// 變成了前臺 Service 服務(wù)
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、執(zhí)行效果
執(zhí)行上述應(yīng)用后 , 可以看到啟動了兩個應(yīng)用 , 干掉應(yīng)用后 , 可以被遠(yuǎn)程進程拉起 , 干掉遠(yuǎn)程進程 , 遠(yuǎn)程進程可以本主進程服務(wù)拉起 ;
三、 源碼資源
源碼資源 :
GitHub 地址 : https://github.com/han1202012/Two_Progress_Alive
CSDN 源碼快照 : https://download.csdn.net/download/han1202012/16623056
————————————————
版權(quán)聲明:本文為CSDN博主「韓曙亮」的原創(chuàng)文章,遵循CC 4.0 BY-SA版權(quán)協(xié)議,轉(zhuǎn)載請附上原文出處鏈接及本聲明。
原文鏈接:https://blog.csdn.net/shulianghan/article/details/115604667