bind Service 基礎

一、bind service涉及到的數據結構

1、概覽
ServiceRecord首先針對intent,維護一個IntentBindRecord map; 在IntentBindRecord中又針對ProcessRecord,維護一個AppBindRecord的map ; 在AppBindRecord中維護一個ConnectionRecord的集合。

主要結構如下圖
在這裏插入圖片描述
2、細節
1)ConnectionRecord
描述單個service的綁定,持有上一級AppBindRecord的引用,對應客戶端的ServiceConnection

final AppBindRecord binding;    // The application/service binding.
  • 添加connection : bindServiceLocked

  • 移除connection : removeConnectionLocked,具體見 2)中代碼

2)AppBindRecord
描述一個Service與Client application的關聯

final ServiceRecord service;    // The running service.
final IntentBindRecord intent;  // The intent we are bound to.
final ProcessRecord client;     // Who has started/bound the service.
final ArraySet<ConnectionRecord> connections = new ArraySet<>(); // All ConnectionRecord for this client.
  • 添加app: retrieveAppBindingLocked
    根據intent找到對應的IntentBindRecord,再根據ProcessRecord在IntentBindRecord中找對應的AppBindRecord,存在則返回,不存在則創建
public AppBindRecord retrieveAppBindingLocked(Intent intent,
           ProcessRecord app) {
       Intent.FilterComparison filter = new Intent.FilterComparison(intent);
       IntentBindRecord i = bindings.get(filter);
       if (i == null) {
           i = new IntentBindRecord(this, filter);
           bindings.put(filter, i);
       }
       AppBindRecord a = i.apps.get(app);
       if (a != null) {
           return a;
       }
       a = new AppBindRecord(this, i, app);
       i.apps.put(app, a);
       return a;
   }
  • 移除app: removeConnectionLocked
    先從AppBindRecord移除當前ConnectionRecord,若移除完後connections 集合爲空,則從對應的IntentBindRecord中移除當前AppBindRecord
void removeConnectionLocked(ConnectionRecord c, ProcessRecord skipApp,
           ActivityServiceConnectionsHolder skipAct) {
       IBinder binder = c.conn.asBinder();
       AppBindRecord b = c.binding;
       ......
       if (b.connections.size() == 0) {
           b.intent.apps.remove(b.client);
       }
   }

3)IntentBindRecord
綁定到Service的特定Intent

/** All apps that have bound to this Intent. */
final ArrayMap<ProcessRecord, AppBindRecord> apps = new ArrayMap<ProcessRecord, AppBindRecord>();
  • 添加binding: retrieveAppBindingLocked
    根據intent找到對應的IntentBindRecord,若不存在則創建,並添加到ServiceRecord的bindings map中
  • 移除binding Service銷燬時clear

4)ServiceRecord
對應於App的Service

final ArrayMap<Intent.FilterComparison, IntentBindRecord> bindings = new ArrayMap<Intent.FilterComparison, IntentBindRecord>();
// All active bindings to the service,代表bind 這個service的鏈接
private final ArrayMap<IBinder, ArrayList<ConnectionRecord>> connections = new ArrayMap<IBinder, ArrayList<ConnectionRecord>>();

二、相關flags

1、BIND_TREAT_LIKE_ACTIVITY
將binding 視爲持有一個activity,unbinding視爲activity在後臺。這意味着unbinding時,進程將會進入activity的LRU list而不是常規的LRU list,從而更有可能保持這個進程。這個通常用在輸入法進程,以便更快捷的切換鍵盤。

需要校驗calling MANAGE_ACTIVITY_STACKS 權限

if ((flags&Context.BIND_TREAT_LIKE_ACTIVITY) != 0) {
    s.app.treatLikeActivity = true;
}
 // This could have made the service more important.
 mAm.updateLruProcessLocked(s.app,
         (callerApp.hasActivitiesOrRecentTasks() && s.app.hasClientActivities())
             || (callerApp.getCurProcState() <= ActivityManager.PROCESS_STATE_TOP && (flags & Context.BIND_TREAT_LIKE_ACTIVITY) != 0),
          b.client);

2、BIND_SCHEDULE_LIKE_TOP_APP
此標誌僅用於系統調整IME(以及與top應用程序緊密配合的任何進程外用戶可見組件)的調度策略。所以託管此類服務的UI能夠擁有top app一樣的調度策略

僅限於系統調用,否則會拋出安全異常

3、BIND_ALLOW_WHITELIST_MANAGEMENT
允許綁定Service應用程序管理白名單,例如臨時繞過省電模式

僅限於系統調用,否則會拋出安全異常

if ((c.flags&Context.BIND_ALLOW_WHITELIST_MANAGEMENT) != 0) {
     s.whitelistManager = true;
}
// If this connection requested whitelist management, see if we should
// now clear that state.
if ((c.flags&Context.BIND_ALLOW_WHITELIST_MANAGEMENT) != 0) {
   s.updateWhitelistManager();
   if (!s.whitelistManager && s.app != null) {
       updateWhitelistManagerLocked(s.app);
   }
}

4、BIND_ALLOW_BACKGROUND_ACTIVITY_STARTS
允許綁定Service的進程啓動後臺Activity,需要校驗android.Manifest.permission#START_ACTIVITIES_FROM_BACKGROUND

5、BIND_EXTERNAL_SERVICE
這將 Service綁定到調用的應用package中,而非聲明Service的package,即Service將在調用者進程package和userId下運行。

1)Service的聲明需要以下幾點,以下三個屬性皆必須爲true

<service
    android:name=".XXXService"
    android:exported="true"
    android:externalService="true"
    android:isolatedProcess="true" />

2)綁定Service需要加入這個flag

bindService(intent, mConnection, Context.BIND_AUTO_CREATE | Context.BIND_EXTERNAL_SERVICE);

涉及到的校驗代碼在retrieveServiceLocked中

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章