1 概述
????????進(jìn)程在內(nèi)存中時(shí)活動(dòng)主要有五種狀態(tài),即前臺進(jìn)程扔涧、可見進(jìn)程园担、服務(wù)進(jìn)程、后臺進(jìn)程枯夜、空進(jìn)程弯汰,這幾種狀態(tài)的進(jìn)程優(yōu)先級由高到低,oom_adj值由低到高(在ProcessList定義)湖雹,然后Android系統(tǒng)會根據(jù)當(dāng)前系統(tǒng)資源和進(jìn)程oom_adj值來回收相應(yīng)的進(jìn)程咏闪,前臺進(jìn)程一般不會被回收,空進(jìn)程最容易被回收摔吏,這種管理規(guī)則就是"傳說中"的Low Memory Killer鸽嫂。
????????各種類型進(jìn)程的oom_adj值
????????注:優(yōu)先級1表示最高級,普通進(jìn)程的oom_adj>=0征讲,系統(tǒng)進(jìn)程oom_adj<0据某,系統(tǒng)會根據(jù)相應(yīng)的內(nèi)存閥值對符合某段oom_adj值的進(jìn)程進(jìn)行回收。另外诗箍,oom_adj值也會隨著占用物理內(nèi)存越大而增大癣籽,系統(tǒng)進(jìn)程絕對不會被系統(tǒng)殺死。
2 常見的甭俗妫活拉起方式
????????了解進(jìn)程被殺死的相關(guān)場景后筷狼,相信大家對進(jìn)程保活已經(jīng)有了初步的認(rèn)識匠童,接下來我將給大家介紹一下桑逝,現(xiàn)在市面上存在的各種常見的保活拉起方式俏让,這些保活方式如下:
????a) 將Service設(shè)置為前臺服務(wù)
????b) 在service的onstart方法里返回STATR_STICK
????c) 添加Manifest文件屬性值為android:persistent=“true”
????d) 覆寫Service的onDestroy方法
????e) 監(jiān)聽一堆系統(tǒng)靜態(tài)廣播
????f) 監(jiān)聽第三方應(yīng)用的靜態(tài)廣播
????g) AlarmManager喚醒
????h) 賬戶同步茬暇,定時(shí)喚醒
????i) 1像素懸浮層
????j) GCM或其它3方推送
????k) 應(yīng)用間互相拉起
????l) 心跳喚醒
????m)Native進(jìn)程拉起
????n) 雙進(jìn)程守護(hù)**
2.1 將Service設(shè)置為前臺服務(wù)
思路:啟用前臺服務(wù)首昔,主要是startForeground()
保活程度:一般情況下不被殺糙俗,部分定制ROM會在應(yīng)用切到后臺即殺勒奇,會被 force stop 殺死
代碼實(shí)現(xiàn):
Notificationnotification = newNotification(R.drawable.queen2, "有消息來了", System.currentTimeMillis());
notification.setLatestEventInfo(this, "雙11,上天貓巧骚!", "一律5折", null);
//設(shè)置通知默認(rèn)效果
notification.flags = Notification.FLAG_SHOW_LIGHTS;
startForeground(1, notification);
2.2 在service的onstart方法里返回STATR_STICK
思路:其實(shí)就是onStartCommand中返回STATR_STICK
鄙薜撸活程度:有次數(shù)和時(shí)間的限制格二,會被 force stop 殺死
代碼實(shí)現(xiàn):
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
???// TODO Auto-generated method stub
???return START_STICKY;
???//return super.onStartCommand(intent, flags, startId);
}
2.3 添加Manifest文件屬性值為android:persistent=“true”
代碼實(shí)現(xiàn)(清單文件中配置):
保活程度:一般情況下不被殺竣蹦,會被 force stop 殺死
????????注意:該方法需要系統(tǒng)簽名
2.4 覆寫Service的onDestroy方法
思路:在onDestroy中再次啟動(dòng)該服務(wù)
倍ゲ拢活程度:很弱,只在兩種情況下work:正在運(yùn)行里殺服務(wù)痘括、DDMS里stop進(jìn)程
代碼實(shí)現(xiàn):
@Override
public void onDestroy() {
???Intent intent = new Intent(this, KeeLiveService.class);
???startService(intent);
???super.onDestroy();
}
2.5 監(jiān)聽一堆系統(tǒng)靜態(tài)廣播
思路:
????????在發(fā)生特定系統(tǒng)事件時(shí)长窄,系統(tǒng)會發(fā)出響應(yīng)的廣播,通過在 AndroidManifest 中“靜態(tài)”注冊對應(yīng)的廣播監(jiān)聽器纲菌,即可在發(fā)生響應(yīng)事件時(shí)拉活挠日。
????????可以監(jiān)聽的系統(tǒng)靜態(tài)廣播列表如下:
保活強(qiáng)度:
????????我們可以發(fā)現(xiàn)翰舌,這個(gè)方法都是監(jiān)聽系統(tǒng)的一些廣播嚣潜,所以我們需要在我們的應(yīng)用中注冊靜態(tài)廣播,但是靜態(tài)廣播又會出現(xiàn)問題椅贱,那就是在4.0版本以上懂算,沒有啟動(dòng)過的應(yīng)用或Force-Stop后收不到靜態(tài)廣播,也就是說4.0以后夜涕,如果我們應(yīng)用從未啟動(dòng)過犯犁,或者被Force-Stop殺死過,是無法接收到靜態(tài)廣播的女器。
????????如果是兩個(gè)應(yīng)用相互拉起酸役,那么在一個(gè)應(yīng)用內(nèi)可發(fā)送帶FLAG_INCLUDE_STOPPED_PACKAGES的Intent,那即使另一個(gè)應(yīng)用也是以上兩種情況驾胆,也可以接收到系統(tǒng)的廣播
????????應(yīng)用1的代碼實(shí)現(xiàn):
//應(yīng)用1涣澡,發(fā)送拉起服務(wù)的廣播
Intent intent = new Intent();
intent.setAction("com.action.keepLive");
intent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES);
this.sendBroadcast(intent);
應(yīng)用2的代碼實(shí)現(xiàn):
public class KeepLiveReceiver extends BroadcastReceiver{
???//應(yīng)用2中,接受應(yīng)用1發(fā)送的廣播丧诺,進(jìn)行服務(wù)的拉起
???@Override
???public void onReceive(Contextcontext, Intent intent) {
??????? Intent i = newIntent(context, KeeLiveService.class);
??????? context.startService(i);
???}
}
2.6 監(jiān)聽第三方應(yīng)用的靜態(tài)廣播
思路:
????????通過反編譯第三方 Top 應(yīng)用入桂,如:手機(jī)QQ、微信驳阎、支付寶抗愁、UC瀏覽器等,以及友盟呵晚、信鴿蜘腌、個(gè)推等 SDK,找出它們外發(fā)的廣播饵隙,在應(yīng)用中進(jìn)行監(jiān)聽撮珠,這樣當(dāng)這些應(yīng)用發(fā)出廣播時(shí),就會將我們的應(yīng)用拉活金矛。
毙炯保活強(qiáng)度:
????????該方案的局限性除與系統(tǒng)廣播一樣的因素外勺届,主要受如下因素限制:
????1) 反編譯分析過的第三方應(yīng)用的多少
????2) 第三方應(yīng)用的廣播屬于應(yīng)用私有,當(dāng)前版本中有效的廣播娶耍,在后續(xù)版本隨時(shí)就可能被移除或被改為不外發(fā)免姿,這些因素都影響了拉活的效果。
2.7 AlarmManager喚醒
思路:通過AlarmManager設(shè)置一個(gè)定時(shí)器伺绽,定時(shí)的喚醒服務(wù)
????**毖荩活強(qiáng)度:**killBackgroundProcess下,大部分情況work奈应,
????不敵force-stop澜掩,鬧鐘會被清除。
代碼實(shí)現(xiàn):
public void startKeepLiveService(Context context, int timeMillis, String action) {
???//獲取AlarmManager系統(tǒng)服務(wù)
???AlarmManager alarmManager = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
???//包裝Intent
???Intent intent = newIntent(context,KeepLiveServie.class);
???intent.setAction(action);
???PendingIntent pendingIntent = PendingIntent.getService(context,0,intent,
PendingIntent.FLAG_UPDATE_CURRENT);
???//添加到AlarmManager? ? ?
????alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(), timeMillis,pendingIntent);
}
2.8 賬戶同步杖挣,定時(shí)喚醒
思路:android系統(tǒng)里有一個(gè)賬戶系統(tǒng)肩榕,系統(tǒng)定期喚醒賬號更新服務(wù),同步的事件間隔是有限制的惩妇,最短1分鐘株汉。
難點(diǎn):需要手動(dòng)設(shè)置賬戶,你如何騙你的用戶給你手動(dòng)設(shè)置賬戶完了之后不卸載你歌殃,必須聯(lián)網(wǎng)
代碼實(shí)現(xiàn):
????① 建立數(shù)據(jù)同步系統(tǒng)(ContentProvider)
????????通過一個(gè)ContentProvider用來作數(shù)據(jù)同步乔妈,由于并沒有實(shí)際數(shù)據(jù)同步,所以此處就直接建立一個(gè)空的ContentProvider即可氓皱。
public class XXAccountProvider extends ContentProvider{
???public static final String AUTHORITY = "包名.provider";
???public static final String CONTENT_URI_BASE = "content://"+ AUTHORITY;
???public static final String TABLE_NAME = "data";
???public static final Uri CONTENT_URI = Uri.parse(CONTENT_URI_BASE + "/"+TABLE_NAME);
???@Override
???public boolean onCreate() {
??????? return true;
???}
???@Nullable
???@Override
???public Cursor query(Uri uri, String[] projection,String selection, String[] selectionArgs, String sortOrder) {
??????? return null;
???}
???@Nullable
???@Override
???public String getType(Uri uri) {
??????? return newString();
???}
???@Nullable
???@Override
???public Uri insert(Uri uri, ContentValues values) {
??????? return null;
???}
???@Override
???public int delete(Uri uri, String selection, String[] selectionArgs) {
??????? return 0;
???}
???@Override
???public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
??????? return 0;
???}
}
然后再M(fèi)anifest中聲明
????② 建立Sync系統(tǒng)(SyncAdapter)
????????通過實(shí)現(xiàn)SyncAdapter這個(gè)系統(tǒng)服務(wù)后, 利用系統(tǒng)的定時(shí)器對程序數(shù)據(jù)ContentProvider進(jìn)行更新路召,具體步驟為:
- 創(chuàng)建Sync服務(wù)
public class XXSyncService extends Service{
???private static final Object sSyncAdapterLock = newObject();
???private static XXSyncAdapter sSyncAdapter = null;
???@Override
???public void onCreate() {
??????? synchronized(sSyncAdapterLock) {
??????????? if (sSyncAdapter == null) {
??????????????? sSyncAdapter = newXXSyncAdapter(getApplicationContext(), true);
??????????? }
??????? }
???}
???@Override
???public IBinder onBind(Intent intent) {
??????? return sSyncAdapter.getSyncAdapterBinder();
???}
???static class XXSyncAdapter extends AbstractThreadedSyncAdapter{
??????? public XXSyncAdapter(Context context, boolean autoInitialize) {
??????????? super(context, autoInitialize);
??????? }
??????? @Override
??????? public void onPerformSync(Account account, Bundle extras, String authority, ContentProviderClient provider, SyncResult syncResult) {
??????????? getContext().getContentResolver().notifyChange(XXAccountProvider.CONTENT_URI, null, false);
??????? }
???}
}
??? 聲明Sync服務(wù)
????????其中sync_adapter為:
????????參數(shù)說明:
????android:contentAuthority 指定要同步的ContentProvider在其AndroidManifest.xml文件中有個(gè)android:authorities屬性。
????android:accountType 表示進(jìn)行同步的賬號的類型波材。
????android:userVisible 設(shè)置是否在“設(shè)置”中顯示
????android:supportsUploading 設(shè)置是否必須notifyChange通知才能同步
????android:allowParallelSyncs 是否支持多賬號同時(shí)同步
????android:isAlwaysSyncable 設(shè)置所有賬號的isSyncable為1
????android:syncAdapterSettingsAction 指定一個(gè)可以設(shè)置同步的activity的Action股淡。
賬戶調(diào)用Sync服務(wù)
??? 首先配置好Account(第三步),然后再通過ContentProvider實(shí)現(xiàn)
??? 手動(dòng)更新
public void triggerRefresh() {
???Bundle b = newBundle();
???b.putBoolean(ContentResolver.SYNC_EXTRAS_MANUAL, true);
???b.putBoolean(ContentResolver.SYNC_EXTRAS_EXPEDITED, true);
???ContentResolver.requestSync(account, CONTENT_AUTHORITY, b);
}
添加賬號
Account account = AccountService.GetAccount();
AccountManager accountManager = (AccountManager)context.getSystemService(Context.ACCOUNT_SERVICE);
accountManager.addAccountExplicitly(...)
同步周期設(shè)置
ContentResolver.setIsSyncable(account, CONTENT_AUTHORITY, 1);
ContentResolver.setSyncAutomatically(account, CONTENT_AUTHORITY, true);
ContentResolver.addPeriodicSync(account, CONTENT_AUTHORITY, new Bundle(), SYNC_FREQUENCY);
????③ 建立賬號系統(tǒng)(Account Authenticator)
????????通過建立Account賬號廷区,并關(guān)聯(lián)SyncAdapter服務(wù)實(shí)現(xiàn)同步
- 創(chuàng)建Account服務(wù)
public class XXAuthService extends Service{
???private XXAuthenticator mAuthenticator;
???@Override
???public void onCreate() {
??????? mAuthenticator = new XXAuthenticator(this);
???}
???private XXAuthenticator getAuthenticator() {
??????? if (mAuthenticator == null)
??????????? mAuthenticator = new XXAuthenticator(this);
??????? return mAuthenticator;
???}
???@Override
???public IBinder onBind(Intent intent) {
??????? returngetAuthenticator().getIBinder();
???}
???class XXAuthenticator extends AbstractAccountAuthenticator {
??????? private final Context context;
??????? private AccountManager accountManager;
??????? public XXAuthenticator(Contextcontext) {
??????????? super(context);
??????????? this.context = context;
??????????? accountManager = AccountManager.get(context);
??????? }
??????? @Override
??????? public Bundle addAccount(AccountAuthenticatorResponse response, String accountType, String authTokenType, String[] requiredFeatures, Bundle options) throwsNetworkErrorException?
????????{
??????????? // 添加賬號 示例代碼
??????????? final Bundle bundle = newBundle();
??????????? final Intent intent = newIntent(context, AuthActivity.class);
???????????intent.putExtra(AccountManager.KEY_ACCOUNT_AUTHENTICATOR_RESPONSE, response);
???????????bundle.putParcelable(AccountManager.KEY_INTENT, intent);
??????????? return bundle;
??????? }
??????? @Override
??????? public Bundle getAuthToken(AccountAuthenticatorResponse response, Account account, String authTokenType, Bundle options) throws NetworkErrorException {
??????????? // 認(rèn)證 示例代碼
??????????? String authToken = accountManager.peekAuthToken(account, getString(R.string.account_token_type));
??????????? //if not, might be expired, register again
??????????? if(TextUtils.isEmpty(authToken)) {
??????????????? final String password = accountManager.getPassword(account);
??????????????? if (password != null) {
??????????????????? //get new token
??????????????????? authToken = account.name + password;
??????????????? }
??????????? }
??????????? //without password, need to sign again
??????????? final Bundle bundle = newBundle();
??????????? if(!TextUtils.isEmpty(authToken)) {
???????????????bundle.putString(AccountManager.KEY_ACCOUNT_NAME, account.name);
???????????????bundle.putString(AccountManager.KEY_ACCOUNT_TYPE, account.type);
???????????????bundle.putString(AccountManager.KEY_AUTHTOKEN, authToken);
??????????????? return bundle;
??????????? }
??????????? //no account data at all, need to do a sign
??????????? final Intent intent = newIntent(context, AuthActivity.class);
???????????intent.putExtra(AccountManager.KEY_ACCOUNT_AUTHENTICATOR_RESPONSE, response);
???????????intent.putExtra(AuthActivity.ARG_ACCOUNT_NAME, account.name);
???????????bundle.putParcelable(AccountManager.KEY_INTENT, intent);
??????????? return bundle;
??????? }
??????? @Override
??????? public String getAuthTokenLabel(StringauthTokenType) {
//??????????? throw newUnsupportedOperationException();
????????? ??return null;
??????? }
??????? @Override
??????? public Bundle editProperties(AccountAuthenticatorResponseresponse, String accountType) {
??????????? return null;
??????? }
??????? @Override
??????? public Bundle confirmCredentials(AccountAuthenticatorResponse response, Account account, Bundle options) throws NetworkErrorException {
??????????? return null;
??????? }
??????? @Override
??????? public Bundle updateCredentials(AccountAuthenticatorResponse response, Account account, String authTokenType, Bundle options) throws NetworkErrorException {
??????????? return null;
??????? }
??????? @Override
??????? public Bundle hasFeatures(AccountAuthenticatorResponse response, Account account, String[] features) throws NetworkErrorException {
??????????? return null;
??????? }
???}
??? 聲明Account服務(wù)
其中authenticator為:
??? 使用Account服務(wù)
??????同SyncAdapter唯灵,通過AccountManager使用
? ? ??申請Token主要是通過 [AccountManager.getAuthToken]系列方法
??????添加賬號則通過[AccountManager.addAccount]
??? - 查看是否存在賬號通過[AccountManager.getAccountsByType]
保活強(qiáng)度:
????????該方案適用于所有的Android 版本隙轻,包括被 fore stop 掉的進(jìn)程也可以進(jìn)行拉活埠帕。最新 Android 版本(Android N)中系統(tǒng)好像對賬戶同步這里做了變動(dòng),該方法不再有效玖绿。
2.9 1像素懸浮層
思路:
????????1像素懸浮層是傳說的QQ黑科技敛瓷,監(jiān)控手機(jī)鎖屏解鎖事件,在屏幕鎖屏?xí)r啟動(dòng)1個(gè)像素的 Activity镰矿,在用戶解鎖時(shí)將 Activity 銷毀掉。注意該 Activity 需設(shè)計(jì)成用戶無感知俘种。通過該方案秤标,可以使進(jìn)程的優(yōu)先級在屏幕鎖屏?xí)r間由4提升為最高優(yōu)先級1绝淡。
保活強(qiáng)度:
????????前臺進(jìn)程苍姜,跟前臺服務(wù)差不多牢酵。需要權(quán)限,不敵force-stop衙猪。
實(shí)現(xiàn)代碼:
????????首先定義 Activity馍乙,并設(shè)置 Activity 的大小為1像素:
public class KeepLiveActivityextendsAppCompatActivity{
??? private static final StringTAG = "keeplive";
??? @Override
??? protected void onCreate(Bundle savedInstanceState) {
??????? super.onCreate(savedInstanceState);
??????? //setContentView(R.layout.activity_main);
??????? Window window = getWindow();
???????window.setGravity(Gravity.LEFT|Gravity.TOP);
??????? WindowManager.LayoutParamsparams = window.getAttributes();
??????? params.x = 0;
??????? params.y = 0;
??????? params.height = 1;
??????? params.width = 1;
???????window.setAttributes(params);
??? }
}
其次,從 AndroidManifest 中通過如下屬性垫释,排除 Activity 在 RecentTask 中的顯示:
????????最后丝格,控制 Activity 為透明:
????????Activity 啟動(dòng)與銷毀時(shí)機(jī)的控制:
public class KeepLiveReceiver extends BroadcastReceiver{
??? private Context mContext;
??? @Override
??? public void onReceive(Context context, Intentintent) {
??????? String action = intent.getAction();
??????? if(action.equals(Intent.ACTION_SCREEN_OFF)){
???????????KeepLiveManeger.getInstance(mContext).startKeepLiveActivity();
??????? }else if(action.equals(Intent.ACTION_USER_PRESENT)) {
???????????KeepLiveManeger.getInstance(mContext).destroyKeepLiveActivity();
??????? }
???????KeepLiveManeger.getInstance(mContext).startKeepLiveService();
??? }
}
2.10 應(yīng)用間互相拉起
思路:
????????app之間知道包名就可以相互喚醒了,比如你殺了我qq棵譬,只要微信還在就能確保隨時(shí)喚醒qq显蝌。還有百度全系app都通過bdshare實(shí)現(xiàn)互拉互保,自定義一個(gè)廣播订咸,定時(shí)發(fā)曼尊,其他app收廣播自起等。
2.11 心跳喚醒
思路:微信痹嗳拢活技術(shù)骆撇,依賴系統(tǒng)特性:長連接網(wǎng)絡(luò)回包機(jī)制
保活強(qiáng)度:不敵force-stop父叙,需要網(wǎng)絡(luò)神郊,API level >= 23的doze模式會關(guān)閉所有的網(wǎng)絡(luò)
代碼實(shí)現(xiàn):
public class HeartbeatService extends Service implements Runnable{
??? private Thread mThread;
??? public int count = 0;
??? private boolean isTip = true;
??? private static String mRestMsg;
??? private static String KEY_REST_MSG = "KEY_REST_MSG";
??? @Override
??? public void run() {
??????? while (true) {
??????????? try{
??????????????? if (count > 1) {
??????????????????? count =1;
??????????????????? if(isTip) {
??????????????????????? //判斷應(yīng)用是否在運(yùn)行
???????????????????????ActivityManager am = (ActivityManager)getSystemService(Context.ACTIVITY_SERVICE);
???????????????????????List list = am.getRunningTasks(3);
??????????????????????? for(RunningTaskInfo info :list) {
???????????? ???????????????if (info.topActivity.getPackageName().equals("org.yhn.demo")) {
??????????????????????????????? //通知應(yīng)用,顯示提示“連接不到服務(wù)器”
???????????????????????????????Intent intent = new Intent("org.yhn.demo");
???????????????????????????????intent.putExtra("msg", true);
???????????????????????????????sendBroadcast(intent);
??????????????????????????????? break;
??????????????????????????? }
??????????????????????? }
??????????????????????? isTip = false;
??????????????????? }
??????????????? }
??????????? ????if (mRestMsg != "" && mRestMsg != null) {
??????????????????? //向服務(wù)器發(fā)送心跳包
???????????????????sendHeartbeatPackage(mRestMsg);
??????????????????? count += 1;
??????????????? }
??????????????? Thread.sleep(1000 * 3);
??????????? }catch(InterruptedException e){
??????????????? e.printStackTrace();
??????????? }
??????? }
??? }
??? private void sendHeartbeatPackage(String msg) {
??????? HttpGet httpGet = new HttpGet(msg);
??????? DefaultHttpClient httpClient = new DefaultHttpClient();
??????? // 發(fā)送請求
??????? HttpResponse httpResponse = null;
??????? try{
??????????? httpResponse = httpClient.execute(httpGet);
??????? }catch(Exception e) {
??????????? e.printStackTrace();
??????? }
??????? if (httpResponse == null) {
??????????? return;
??????? }
??????? // 處理返回結(jié)果
??????? final int responseCode = httpResponse.getStatusLine().getStatusCode();
??????? if(responseCode == HttpStatus.SC_OK) {
??????????? //只要服務(wù)器有回應(yīng)就OK
??????????? count = 0;
??????????? isTip = true;
??????? }else{
??????????? Log.i("@qi", "responseCode" + responseCode);
??????? }
??? }
??? @Override
??? public IBinder onBind(Intent intent) {
??????? return null;
??? }
??? @Override
??? public void onCreate() {
??????? super.onCreate();
??? }
??? @Override
??? public void onDestroy() {
??????? super.onDestroy();
??? }
??? public void onStart(Intent intent, intstartId) {
??????? Log.i("@qi", "service onStart");
??????? //從本地讀取服務(wù)器的URL高每,如果沒有就用傳進(jìn)來的URL
??????? mRestMsg = getRestMsg();
??????? if (mRestMsg == null || mRestMsg == "") {
??????????? mRestMsg = intent.getExtras().getString("url");
??????? }
??????? setRestMsg(mRestMsg);
??????? mThread = new Thread(this);
??????? mThread.start();
??????? count = 0;
??????? super.onStart(intent, startId);
??? }
??? public String getRestMsg() {
??????? SharedPreferences prefer = getSharedPreferences("settings.data", Context.MODE_PRIVATE);
??????? return prefer.getString(KEY_REST_MSG, "");
??? }
??? public void setRestMsg(String restMsg) {
??????? SharedPreferences prefer = getSharedPreferences("settings.data", Context.MODE_PRIVATE);
??????? SharedPreferences.Editoreditor = prefer.edit();
???????editor.putString(KEY_REST_MSG, restMsg);
??????? editor.commit();
??? }
}
????????最后別忘了注冊Server和GET_TASKS屿岂。
2.12 Native進(jìn)程拉起
思路:開啟native子進(jìn)程,定時(shí)發(fā)intent鲸匿。
币常活強(qiáng)度:單殺可以殺死,force close5.0以上無效带欢,5.0以下部分手機(jī)無效运授,第三方軟件下無效,且無法保證實(shí)時(shí)常駐乔煞。
實(shí)現(xiàn)代碼:
????首先開啟一個(gè)c進(jìn)程吁朦,將需要保活的service名字傳遞進(jìn)去渡贾。
private static void start(Context context, Class<?> daemonClazzName, int interval)?
{
? ? String cmd = context.getDir(BIN_DIR_NAME, Context.MODE_PRIVATE)
????? .getAbsolutePath() + File.separator + DAEMON_BIN_NAME;
?? /* create the command string */
?? StringBuilder cmdBuilder = new StringBuilder();
?? cmdBuilder.append(cmd);
?? cmdBuilder.append(" -p ");
?? cmdBuilder.append(context.getPackageName());
?? cmdBuilder.append(" -s ");
?? cmdBuilder.append(daemonClazzName.getName());
?? cmdBuilder.append(" -t ");
?? cmdBuilder.append(interval);
?? try {
????? Runtime.getRuntime().exec(cmdBuilder.toString()).waitFor();
?? } catch (IOException |InterruptedException e) {
????? Log.e(TAG, "start daemon error: " + e.getMessage());
?? }
}
????????然后定時(shí)給自己主進(jìn)程發(fā)一個(gè)intent逗宜,如果主進(jìn)程掛掉了,就可以順利拉起來保證存活。
while(sig_running)
{
?? interval = interval
?? select_sleep(interval, 0);
?? LOGD(LOG_TAG,"check the service once, interval: %d", interval);
?? /* start service */
?? start_service(package_name, service_name);
}
????????但這只是一個(gè)沒有主動(dòng)權(quán)的消息輪詢器纺讲,說是守護(hù)其實(shí)很勉強(qiáng)擂仍,而且,這是要建立在保證c進(jìn)程不掛的基礎(chǔ)上熬甚,才能輪詢逢渔,但是就目前來看,只有5.0以下的非國產(chǎn)機(jī)才會有這樣的漏洞乡括。也就是說在force close的時(shí)候肃廓,系統(tǒng)忽略c進(jìn)程的存在,5.0以上包括5.0的哪怕源生系統(tǒng)也會連同c進(jìn)程一起清理掉诲泌,國產(chǎn)機(jī)就更不用說了盲赊。就算是這樣,在5.0以下的非國產(chǎn)機(jī)上档礁,如果安裝了獲取root權(quán)限的360\cm的話角钩,也是可以直接清理掉,也就是說會失效呻澜。
????????native進(jìn)程守護(hù)缺點(diǎn)非常明顯递礼,那就是守護(hù)是單向的,也就是說只能a保b羹幸,b保不了a脊髓;a保b也不是在b死了立刻拉起來,要等到了時(shí)間才會去拉栅受。那如何解決這個(gè)native進(jìn)程的缺點(diǎn)呢将硝?那就是通過雙進(jìn)程守護(hù),下一篇我將詳細(xì)講解如何通過linux層來實(shí)現(xiàn)雙進(jìn)程守護(hù)屏镊。
3 參考鏈接
Android進(jìn)程币捞郏活全攻略(上)
http://blog.csdn.net/u012124438/article/details/53141113
【騰訊Bugly干貨分享】Android進(jìn)程保活招式大全
https://blog.csdn.net/Tencent_Bugly/article/details/52192423
探討Android6.0及以上系統(tǒng)APP常駐內(nèi)存(倍妫活)實(shí)現(xiàn)-爭寵篇
http://blog.csdn.net/AndrExpert/article/details/75045678
Android進(jìn)程甭砂眨活總結(jié)
http://blog.csdn.net/superxlcr/article/details/70244803?ref=myread
http://blog.csdn.net/u013263323/article/details/56285475
Android進(jìn)程管理三部曲[2]-進(jìn)程的優(yōu)先級
http://www.reibang.com/p/0501bc2bbe7c
startForeground如何去除通知欄
https://blog.csdn.net/turkeycock/article/details/50911121
https://blog.csdn.net/zjws23786/article/details/51800929
Android懸浮窗實(shí)現(xiàn) 使用WindowManager
https://www.cnblogs.com/mengdd/p/3824782.html
Android Demo: 懸浮窗(支持Android7.0)