自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

一種提高Android應(yīng)用進(jìn)程存活率新方法(上)

移動(dòng)開發(fā) Android
Android系統(tǒng)內(nèi)存不足時(shí),系統(tǒng)會(huì)殺掉一部分進(jìn)程以釋放空間,誰生誰死的這個(gè)生死大權(quán)就是由LMK所決定的,這就是Android系統(tǒng)中的Low Memory Killer,其基于Linux的OOM機(jī)制,其閾值定義如下面所示的lowmemorykiller文件中,當(dāng)然也可以通過系統(tǒng)的init.rc實(shí)現(xiàn)自定義。

[[179902]]

基礎(chǔ)知識(shí)

Android 進(jìn)程優(yōu)先級(jí)

1 進(jìn)程優(yōu)先級(jí)等級(jí)一般分法

  • Activte process
  • Visible Process
  • Service process
  • Background process
  • Empty process

2 Service技巧

  • onStartCommand返回START_STICKY
  • onDestroy中startself
  • Service后臺(tái)變前置,setForground(true)
  • android:persistent = “true”

3 進(jìn)程優(yōu)先級(jí)號(hào)

ProcessList.java

  1. // Adjustment used in certain places where we don't know it yet. 
  2. // (Generally this is something that is going to be cached, but we 
  3. // don't know the exact value in the cached range to assign yet.) 
  4. static final int UNKNOWN_ADJ = 16; 
  5.   
  6. // This is a process only hosting activities that are not visible, 
  7. // so it can be killed without any disruption. 
  8. static final int CACHED_APP_MAX_ADJ = 15; 
  9. static final int CACHED_APP_MIN_ADJ = 9; 
  10.   
  11. // The B list of SERVICE_ADJ -- these are the old and decrepit 
  12. // services that aren't as shiny and interesting as the ones in the A list. 
  13. static final int SERVICE_B_ADJ = 8; 
  14.   
  15. // This is the process of the previous application that the user was in
  16. // This process is kept above other things, because it is very common to 
  17. // switch back to the previous app.  This is important both for recent 
  18. // task switch (toggling between the two top recent apps) as well as normal 
  19. // UI flow such as clicking on a URI in the e-mail app to view in the browser, 
  20. // and then pressing back to return to e-mail. 
  21. static final int PREVIOUS_APP_ADJ = 7; 
  22.   
  23. // This is a process holding the home application -- we want to try 
  24. // avoiding killing it, even if it would normally be in the background, 
  25. // because the user interacts with it so much. 
  26. static final int HOME_APP_ADJ = 6; 
  27.   
  28. // This is a process holding an application service -- killing it will not 
  29. // have much of an impact as far as the user is concerned. 
  30. static final int SERVICE_ADJ = 5; 
  31.   
  32. // This is a process with a heavy-weight application.  It is in the 
  33. // background, but we want to try to avoid killing it.  Value set in 
  34. // system/rootdir/init.rc on startup. 
  35. static final int HEAVY_WEIGHT_APP_ADJ = 4; 
  36.   
  37. // This is a process currently hosting a backup operation.  Killing it 
  38. // is not entirely fatal but is generally a bad idea. 
  39. static final int BACKUP_APP_ADJ = 3; 
  40.   
  41. // This is a process only hosting components that are perceptible to the 
  42. // userand we really want to avoid killing them, but they are not 
  43. // immediately visible. An example is background music playback. 
  44. static final int PERCEPTIBLE_APP_ADJ = 2; 
  45.   
  46. // This is a process only hosting activities that are visible to the 
  47. // user, so we'd prefer they don't disappear. 
  48. static final int VISIBLE_APP_ADJ = 1; 
  49.   
  50. // This is the process running the current foreground app.  We'd really 
  51. // rather not kill it! 
  52. static final int FOREGROUND_APP_ADJ = 0; 
  53.   
  54. // This is a process that the system or a persistent process has bound to
  55. // and indicated it is important. 
  56. static final int PERSISTENT_SERVICE_ADJ = -11; 
  57.   
  58. // This is a system persistent process, such as telephony.  Definitely 
  59. // don't want to kill it, but doing so is not completely fatal. 
  60. static final int PERSISTENT_PROC_ADJ = -12; 
  61.   
  62. // The system process runs at the default adjustment. 
  63. static final int SYSTEM_ADJ = -16; 
  64.   
  65. // Special code for native processes that are not being managed by the system (so 
  66. // don't have an oom adj assigned by the system). 
  67. static final int NATIVE_ADJ = -17;  

Android Low Memory Killer

Android系統(tǒng)內(nèi)存不足時(shí),系統(tǒng)會(huì)殺掉一部分進(jìn)程以釋放空間,誰生誰死的這個(gè)生死大權(quán)就是由LMK所決定的,這就是Android系統(tǒng)中的Low Memory Killer,其基于Linux的OOM機(jī)制,其閾值定義如下面所示的lowmemorykiller文件中,當(dāng)然也可以通過系統(tǒng)的init.rc實(shí)現(xiàn)自定義。

lowmemorykiller.c

  1. static uint32_t lowmem_debug_level = 1; 
  2. static int lowmem_adj[6] = { 
  3.     0, 
  4.     1, 
  5.     6, 
  6.     12, 
  7. }; 
  8. static int lowmem_adj_size = 4; 
  9. static int lowmem_minfree[6] = { 
  10.     3 * 512,    /* 6MB */ 
  11.     2 * 1024,   /* 8MB */ 
  12.     4 * 1024,   /* 16MB */ 
  13.     16 * 1024,  /* 64MB */ 
  14. }; 
  15. static int lowmem_minfree_size = 4;  

① 在Low Memory Killer中通過進(jìn)程的oom_adj與占用內(nèi)存的大小決定要?dú)⑺赖倪M(jìn)程,oom_adj值越小越不容易被殺死。其中,lowmem_minfree是殺進(jìn)程的時(shí)機(jī),誰被殺,則取決于lowmem_adj,具體值得含義參考上面 Android進(jìn)程優(yōu)先級(jí) 所述.

② 在init.rc中定義了init進(jìn)程(系統(tǒng)進(jìn)程)的oom_adj為-16,其不可能會(huì)被殺死(init的PID是1),而前臺(tái)進(jìn)程是0(這里的前臺(tái)進(jìn)程是指用戶正在使用的Activity所在的進(jìn)程),用戶按Home鍵回到桌面時(shí)的優(yōu)先級(jí)是6,普通的Service的進(jìn)程是8.

init.rc

  1. Set init and its forked children's oom_adj. 
  2.     write /proc/1/oom_adj -16  

關(guān)于Low Memory Killer的具體實(shí)現(xiàn)原理可參考Ref-2.

查看某個(gè)App的進(jìn)程

步驟(手機(jī)與PC連接)

  1. adb shell
  2. ps | grep 進(jìn)程名
  3. cat /proc/pid/oom_adj //其中pid是上述grep得到的進(jìn)程號(hào) 

Linux AM命令

am命令:在Android系統(tǒng)中通過adb shell 啟動(dòng)某個(gè)Activity、Service、撥打電話、啟動(dòng)瀏覽器等操作Android的命令.其源碼在Am.java中,在shell環(huán)境下執(zhí)行am命令實(shí)際是啟動(dòng)一個(gè)線程執(zhí)行Am.java中的主函數(shù)(main方法),am命令后跟的參數(shù)都會(huì)當(dāng)做運(yùn)行時(shí)參數(shù)傳遞到主函數(shù)中,主要實(shí)現(xiàn)在Am.java的run方法中。

撥打電話

命令:am start -a android.intent.action.CALL -d tel:電話號(hào)碼

示例:am start -a android.intent.action.CALL -d tel:10086

打開一個(gè)網(wǎng)頁

命令:am start -a android.intent.action.VIEW -d 網(wǎng)址

示例:am start -a android.intent.action.VIEW -d http://www.skyseraph.com

啟動(dòng)一個(gè)服務(wù)

命令:am startservice <服務(wù)名稱>

示例:am startservice -n com.android.music/ com.android.music.MediaPlaybackService

NotificationListenerService

“A service that receives calls from the system when new notifications are posted or removed, or their ranking changed.” From Google

用來監(jiān)聽到通知的發(fā)送以及移除和排名位置變化,如果我們注冊(cè)了這個(gè)服務(wù),當(dāng)系統(tǒng)任何一條通知到來或者被移除掉,我們都能通過這個(gè)service來監(jiān)聽到,甚至可以做一些管理工作。

Android賬號(hào)和同步機(jī)制

屬于Android中較偏冷的知識(shí),具體參考 Ref 3 /4 /5

Android多進(jìn)程

  • 實(shí)現(xiàn):android:process
  • 好處:一個(gè)獨(dú)立的進(jìn)程可以充分利用自己的RAM預(yù)算,使其主進(jìn)程擁有更多的空間處理資源。此外,操作系統(tǒng)對(duì)待運(yùn)行在不同組件中的進(jìn)程是不一樣的。這意味著,當(dāng)系統(tǒng)運(yùn)行在低可用內(nèi)存的條件時(shí),并不是所有的進(jìn)程都會(huì)被殺死
  • 大坑:每一個(gè)進(jìn)程將有自己的Dalvik VM實(shí)例,意味著你不能通過這些實(shí)例共享數(shù)據(jù),至少不是傳統(tǒng)意義上的。例如,靜態(tài)字段在每個(gè)進(jìn)程都有自己的值,而不是你傾向于相信的只有一個(gè)值。
  • 更多詳細(xì)請(qǐng)參考Ref 9

現(xiàn)有方法

網(wǎng)絡(luò)連接保活方法

A. GCM

B. 公共的第三方push通道(信鴿等)

C. 自身跟服務(wù)器通過輪詢,或者長(zhǎng)連接

具體實(shí)現(xiàn)請(qǐng)參考 微信架構(gòu)師楊干榮的”微信Android客戶端后臺(tái)保活經(jīng)驗(yàn)分享” (Ref-1).

雙service(通知欄) 提高進(jìn)程優(yōu)先級(jí)

思路:(API level > 18 )

  • 應(yīng)用啟動(dòng)時(shí)啟動(dòng)一個(gè)假的Service(FakeService), startForeground(),傳一個(gè)空的Notification
  • 啟動(dòng)真正的Service(AlwaysLiveService),startForeground(),注意必須相同Notification ID
  • FakeService stopForeground()

效果:通過adb查看,運(yùn)行在后臺(tái)的服務(wù)其進(jìn)程號(hào)變成了1(優(yōu)先級(jí)僅次于前臺(tái)進(jìn)程)

風(fēng)險(xiǎn):Android系統(tǒng)前臺(tái)service的一個(gè)漏洞,可能在6.0以上系統(tǒng)中修復(fù)

實(shí)現(xiàn):核心代碼如下

  • AlwaysLiveService 常駐內(nèi)存服務(wù)
  1. @Override 
  2.    public int onStartCommand(Intent intent, int flags, int startId) { 
  3.        startForeground(R.id.notify, new Notification()); 
  4.        startService(new Intent(this, FakeService.class)); 
  5.        return super.onStartCommand(intent, flags, startId); 
  6.    }  
  • FakeService 臨時(shí)服務(wù)
  1. public class FakeService extends Service { 
  2.     @Nullable 
  3.     @Override 
  4.     public IBinder onBind(Intent intent) { 
  5.         return null
  6.     } 
  7.   
  8.     @Override 
  9.     public int onStartCommand(Intent intent, int flags, int startId) { 
  10.         startForeground(R.id.notify, new Notification()); 
  11.         stopSelf(); 
  12.         return super.onStartCommand(intent, flags, startId); 
  13.     } 
  14.   
  15.     @Override 
  16.     public void onDestroy() { 
  17.         stopForeground(true); 
  18.         super.onDestroy(); 
  19.     } 
  20.  

Service及時(shí)拉起

AlarmReceiver, ConnectReceiver,BootReceiver等

  • Service設(shè)置(見上面基礎(chǔ)部分)
  • 通過監(jiān)聽系統(tǒng)廣播,如開機(jī),鎖屏,亮屏等重新啟動(dòng)服務(wù)
  • 通過alarm定時(shí)器,啟動(dòng)服務(wù)

守護(hù)進(jìn)程/進(jìn)程互拉

在分析360手機(jī)助手app時(shí),發(fā)現(xiàn)其擁有N多個(gè)進(jìn)程,一個(gè)進(jìn)程kill后會(huì)被其它未kill的進(jìn)程拉起,這也是一種思路吧,雖然有點(diǎn)流氓~

守護(hù)進(jìn)程一般有這樣兩種方式:

  • 多個(gè)java進(jìn)程守護(hù)互拉
  • 底層C守護(hù)進(jìn)程拉起App上層/java進(jìn)程

Linux Am命令開啟后臺(tái)進(jìn)程

一種底層實(shí)現(xiàn)讓進(jìn)程不被殺死的方法,在Android4.4以上可能有兼容性問題,具體參考Ref-7

NotificationListenerService通知

一種需要用戶允許特定權(quán)限的系統(tǒng)拉起方式,4.3以上系統(tǒng)

前臺(tái)浮窗

有朋友提出一種應(yīng)用退出后啟動(dòng)一個(gè)不可交互的浮窗,個(gè)人覺得這種方法是無效的,讀者有興趣可以一試

新方法(AccountSync)

思路

利用Android系統(tǒng)提供的賬號(hào)和同步機(jī)制實(shí)現(xiàn)

效果

  • 通過adb查看,運(yùn)行在后臺(tái)的服務(wù)其進(jìn)程號(hào)變成了1(優(yōu)先級(jí)僅次于前臺(tái)進(jìn)程),能提高進(jìn)程優(yōu)先級(jí),對(duì)比如下圖 

 

 

 

正常情況 

 

 

采用AccountSyncAdapter方法后 

采用AccountSyncAdapter方法后

  • 進(jìn)程被系統(tǒng)kill后,可以由syn拉起

風(fēng)險(xiǎn)

  • SyncAdapter時(shí)間進(jìn)度不高,往往會(huì)因?yàn)槭謾C(jī)處于休眠狀態(tài),而時(shí)間往后調(diào)整,同步間隔最低為1分鐘
  • 用戶可以單獨(dú)停止或者刪除,有些手機(jī)賬號(hào)默認(rèn)是不同步的,需要手動(dòng)開啟

實(shí)現(xiàn) (核心代碼)

1 建立數(shù)據(jù)同步系統(tǒng)(ContentProvider)

通過一個(gè)ContentProvider用來作數(shù)據(jù)同步,由于并沒有實(shí)際數(shù)據(jù)同步,所以此處就直接建立一個(gè)空的ContentProvider即可

  1. public class XXAccountProvider extends ContentProvider { 
  2.     public static final String AUTHORITY = "包名.provider"
  3.     public static final String CONTENT_URI_BASE = "content://" + AUTHORITY; 
  4.     public static final String TABLE_NAME = "data"
  5.     public static final Uri CONTENT_URI = Uri.parse(CONTENT_URI_BASE + "/" + TABLE_NAME); 
  6.   
  7.     @Override 
  8.     public boolean onCreate() { 
  9.         return true
  10.     } 
  11.   
  12.     @Nullable 
  13.     @Override 
  14.     public Cursor query(Uri uri, String[] projection, String selection, 
  15.                         String[] selectionArgs, String sortOrder) { 
  16.         return null
  17.     } 
  18.   
  19.     @Nullable 
  20.     @Override 
  21.     public String getType(Uri uri) { 
  22.         return new String(); 
  23.     } 
  24.   
  25.     @Nullable 
  26.     @Override 
  27.     public Uri insert(Uri uri, ContentValues values) { 
  28.         return null
  29.     } 
  30.   
  31.     @Override 
  32.     public int delete(Uri uri, String selection, String[] selectionArgs) { 
  33.         return 0; 
  34.     } 
  35.   
  36.     @Override 
  37.     public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) { 
  38.         return 0; 
  39.     } 
  40.  

然后再M(fèi)anifest中聲明

  1. <provider 
  2. android:name="**.XXAccountProvider" 
  3. android:authorities="@string/account_auth_provider" 
  4. android:exported="false" 
  5. android:syncable="true"/>  

2 建立Sync系統(tǒng) (SyncAdapter)

通過實(shí)現(xiàn)SyncAdapter這個(gè)系統(tǒng)服務(wù)后, 利用系統(tǒng)的定時(shí)器對(duì)程序數(shù)據(jù)ContentProvider進(jìn)行更新,具體步驟為:

  • 創(chuàng)建Sync服務(wù)
  1. public class XXSyncService extends Service { 
  2.     private static final Object sSyncAdapterLock = new Object(); 
  3.     private static XXSyncAdapter sSyncAdapter = null
  4.     @Override 
  5.     public void onCreate() { 
  6.         synchronized (sSyncAdapterLock) { 
  7.             if (sSyncAdapter == null) { 
  8.                 sSyncAdapter = new XXSyncAdapter(getApplicationContext(), true); 
  9.             } 
  10.         } 
  11.     } 
  12.   
  13.     @Override 
  14.     public IBinder onBind(Intent intent) { 
  15.         return sSyncAdapter.getSyncAdapterBinder(); 
  16.     } 
  17.   
  18.     static class XXSyncAdapter extends AbstractThreadedSyncAdapter { 
  19.         public XXSyncAdapter(Context context, boolean autoInitialize) { 
  20.             super(context, autoInitialize); 
  21.         } 
  22.         @Override 
  23.         public void onPerformSync(Account account, Bundle extras, String authority, ContentProviderClient provider, SyncResult syncResult) { 
  24.             getContext().getContentResolver().notifyChange(XXAccountProvider.CONTENT_URI, nullfalse); 
  25.         } 
  26.     } 
  27.  
  • 聲明Sync服務(wù)
  1. <service 
  2. android:name="**.XXSyncService" 
  3. android:exported="true" 
  4. android:process=":core"
  5. <intent-filter> 
  6. <action 
  7. android:name="android.content.SyncAdapter"/> 
  8. </intent-filter> 
  9. <meta-data 
  10. android:name="android.content.SyncAdapter" 
  11. android:resource="@xml/sync_adapter"/> 
  12. </service>  

其中sync_adapter為:

  1. <sync-adapter xmlns:android="http://schemas.android.com/apk/res/android" 
  2.               android:accountType="@string/account_auth_type" 
  3.               android:allowParallelSyncs="false" 
  4.               android:contentAuthority="@string/account_auth_provide" 
  5.               android:isAlwaysSyncable="true" 
  6.               android:supportsUploading="false" 
  7.               android:userVisible="true"/>  

參數(shù)說明:

android:contentAuthority 指定要同步的ContentProvider在其AndroidManifest.xml文件中有個(gè)android:authorities屬性。

android:accountType 表示進(jìn)行同步的賬號(hào)的類型。

android:userVisible 設(shè)置是否在“設(shè)置”中顯示

android:supportsUploading 設(shè)置是否必須notifyChange通知才能同步

android:allowParallelSyncs 是否支持多賬號(hào)同時(shí)同步

android:isAlwaysSyncable 設(shè)置所有賬號(hào)的isSyncable為1

android:syncAdapterSettingsAction 指定一個(gè)可以設(shè)置同步的activity的Action。

  • 賬戶調(diào)用Sync服務(wù)

首先配置好Account(第三步),然后再通過ContentProvider實(shí)現(xiàn)

手動(dòng)更新

  1. public void triggerRefresh() { 
  2. Bundle b = new Bundle(); 
  3. b.putBoolean(ContentResolver.SYNC_EXTRAS_MANUAL, true); 
  4. b.putBoolean(ContentResolver.SYNC_EXTRAS_EXPEDITED, true); 
  5. ContentResolver.requestSync( 
  6. account, 
  7. CONTENT_AUTHORITY, 
  8. b); 
  9.  

添加賬號(hào)

  1. Account account = AccountService.GetAccount(); 
  2. AccountManager accountManager = (AccountManager) context.getSystemService(Context.ACCOUNT_SERVICE); 
  3. accountManager.addAccountExplicitly(...)  

同步周期設(shè)置

  1. ContentResolver.setIsSyncable(account, CONTENT_AUTHORITY, 1); 
  2. ContentResolver.setSyncAutomatically(account, CONTENT_AUTHORITY, true); 
  3. ContentResolver.addPeriodicSync(account, CONTENT_AUTHORITY, new Bundle(), SYNC_FREQUENCY);  

3 建立賬號(hào)系統(tǒng) (Account Authenticator)

通過建立Account賬號(hào),并關(guān)聯(lián)SyncAdapter服務(wù)實(shí)現(xiàn)同步

接下文

責(zé)任編輯:龐桂玉 來源: 安卓開發(fā)精選
相關(guān)推薦

2016-12-26 18:39:32

Android應(yīng)用進(jìn)程存活率

2022-04-20 08:00:00

深度學(xué)習(xí)數(shù)據(jù)集Hub

2022-11-22 11:18:38

Java虛擬線程

2022-03-10 12:16:14

側(cè)信道內(nèi)存攻擊網(wǎng)絡(luò)攻擊

2021-02-18 18:13:34

LinuxARM樹莓派

2018-10-07 07:00:59

2023-08-08 11:28:06

企業(yè)首席執(zhí)行官

2021-02-18 14:55:06

FuchsiaAndroidLinux

2021-09-26 10:49:27

計(jì)算機(jī)互聯(lián)網(wǎng) 技術(shù)

2024-11-05 08:19:11

深度學(xué)習(xí)神經(jīng)網(wǎng)絡(luò)機(jī)器學(xué)習(xí)

2021-09-27 10:12:42

欺騙防御rMTD網(wǎng)絡(luò)攻擊

2022-05-13 09:40:51

代碼可行應(yīng)用性能

2019-11-23 23:18:20

物聯(lián)網(wǎng)存活率企業(yè)

2010-04-01 09:30:57

2015-08-21 09:14:40

大數(shù)據(jù)

2022-05-26 10:57:51

機(jī)器人人工智能

2019-07-12 13:50:36

物聯(lián)網(wǎng)大數(shù)據(jù)安全

2022-07-07 10:47:16

IngressKubernetes

2024-04-08 12:18:57

訓(xùn)練AI

2023-07-06 15:29:52

數(shù)據(jù)中心能源回收
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)