Service啟動之bindService

話不多說,上代碼(本文基于Android 29 源碼分析):

bindService(Intent(this, MyService::class.java), MyConnection(), Context.BIND_AUTO_CREATE)

其中MyConection代碼為:

inner class MyConnection : ServiceConnection {
        override fun onServiceDisconnected(name: ComponentName?) {
        }

        override fun onServiceConnected(name: ComponentName?, service: IBinder?) {
           
        }

    }

日常操作,就不用解釋了,下面從 bindService 開始,跟蹤源碼,理解整個過程。activity繼承至contextWrapper,contextWrapper其實是contextImpl的代理類,所以bindService直接跟進到contextImpl中,最終到bindServiceCommon:

private boolean bindServiceCommon(Intent service, ServiceConnection conn, int flags,
            String instanceName, Handler handler, Executor executor, UserHandle user) {
        // 后面會分析,這地方記住這個句柄 sd 是 IServiceConnection 對象
        IServiceConnection sd;
        ...
        if (mPackageInfo != null) {
            if (executor != null) {
                sd = mPackageInfo.getServiceDispatcher(conn, getOuterContext(), executor, flags);
            } else {
                sd = mPackageInfo.getServiceDispatcher(conn, getOuterContext(), handler, flags);
            }
        } else {
            throw new RuntimeException("Not supported in system context");
        }
        validateServiceIntent(service);
        try {
            IBinder token = getActivityToken();
            if (token == null && (flags&BIND_AUTO_CREATE) == 0 && mPackageInfo != null
                    && mPackageInfo.getApplicationInfo().targetSdkVersion
                    < android.os.Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
                flags |= BIND_WAIVE_PRIORITY;
            }
          //準備離開本進程,提前打個招呼,做些準備操作
            service.prepareToLeaveProcess(this);
          // 關鍵點 1:跳轉(zhuǎn)到AMS處理,開始了跨進程之旅
            int res = ActivityManager.getService().bindIsolatedService(
                mMainThread.getApplicationThread(), getActivityToken(), service,
                service.resolveTypeIfNeeded(getContentResolver()),
                sd, flags, instanceName, getOpPackageName(), user.getIdentifier());
            if (res < 0) {
                throw new SecurityException(
                        "Not allowed to bind to service " + service);
            }
            return res != 0;
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

關鍵點1處注意幾個參數(shù):

getApplicationThread: 都知道進程啟動、activity啟動都會有一個ApplicationThread,同理這地方也是,在啟動service的時候依然是走到 ActivityThread,走生命周期。
getActivityToken:每一個Activity都有一個token,該token會在ActivityRecord中保存,由WMS有關,這地方就是找到指定的Activity
sd:IServiceConnection對象,后面會用到

接著走到AMS,看一下AMS怎么做的處理:

public int bindIsolatedService(IApplicationThread caller, IBinder token, Intent service,
            String resolvedType, IServiceConnection connection, int flags, String instanceName,
            String callingPackage, int userId) throws TransactionTooLargeException {
                ...
        synchronized(this) {
            return mServices.bindServiceLocked(caller, token, service,
                    resolvedType, connection, flags, instanceName, callingPackage, userId);
        }
    }

參數(shù)對應上,又調(diào)用 了bindServiceLocked方法,go on:

int bindServiceLocked(IApplicationThread caller, IBinder token, Intent service,
            String resolvedType, final IServiceConnection connection, int flags,
            String instanceName, String callingPackage, final int userId)
            throws TransactionTooLargeException {
        ...
          //獲取調(diào)用者線程
        final ProcessRecord callerApp = mAm.getRecordForAppLocked(caller);
        ...
          //本質(zhì)上就是創(chuàng)建一個ServiceRecord對象,該對象實現(xiàn)了binder接口
        ServiceLookupResult res =
            retrieveServiceLocked(service, instanceName, resolvedType, callingPackage,
                    Binder.getCallingPid(), Binder.getCallingUid(), userId, true,
                    callerFg, isBindExternal, allowInstant);
        if (res == null) {
            return 0;
        }
        if (res.record == null) {
            return -1;
        }
        ServiceRecord s = res.record;
       ...
        try {
            ...
            //關鍵點1 
            AppBindRecord b = s.retrieveAppBindingLocked(service, callerApp);
            ConnectionRecord c = new ConnectionRecord(b, activity,
                    connection, flags, clientLabel, clientIntent,
                    callerApp.uid, callerApp.processName, callingPackage);

            IBinder binder = connection.asBinder();
            s.addConnection(binder, c);
            b.connections.add(c);
            if (activity != null) {
                activity.addConnection(c);
            }
            b.client.connections.add(c);
            c.startAssociationIfNeeded();
            if ((c.flags&Context.BIND_ABOVE_CLIENT) != 0) {
                b.client.hasAboveClient = true;
            }
            if ((c.flags&Context.BIND_ALLOW_WHITELIST_MANAGEMENT) != 0) {
                s.whitelistManager = true;
            }
            if ((flags & Context.BIND_ALLOW_BACKGROUND_ACTIVITY_STARTS) != 0) {
                s.setHasBindingWhitelistingBgActivityStarts(true);
            }
            if (s.app != null) {
                updateServiceClientActivitiesLocked(s.app, c, true);
            }
            ArrayList<ConnectionRecord> clist = mServiceConnections.get(binder);
            if (clist == null) {
                clist = new ArrayList<>();
                mServiceConnections.put(binder, clist);
            }
            clist.add(c);

          // 關鍵點2 
            if ((flags&Context.BIND_AUTO_CREATE) != 0) {
                s.lastActivity = SystemClock.uptimeMillis();
                if (bringUpServiceLocked(s, service.getFlags(), callerFg, false,
                        permissionsReviewRequired) != null) {
                    return 0;
                }
            }

           ...
        return 1;
    }

該方法較長,分析關鍵 的流程,在關鍵點1處,創(chuàng)建了ConnectionRecord對象,從名稱可看出就是我們bind service方法調(diào)用傳的 Connection對象,不過這地方是包裝的IServiceConnection ,這個就是上面說的sd對象,先知道是包裝了Connection的對象,后面會分析,接著一些flag相關。關鍵點2 這個是真正重要的地方,先看flag判斷,(flags&Context.BIND_AUTO_CREATE) != 0,如果參數(shù)是Context.BIND_AUTO_CREATE,就會走到bringUpServiceLocked,Context.BIND_AUTO_CREATE就是bindeservice方法最后一個參數(shù),

bindService(Intent(this, MyService::class.java), MyConnection(), Context.BIND_AUTO_CREATE)

這個參數(shù)的意義就是,自動startService,在執(zhí)行綁定操作,繼續(xù)跟進bringUpServiceLocked,

private String bringUpServiceLocked(ServiceRecord r, int intentFlags, boolean execInFg,
            boolean whileRestarting, boolean permissionsReviewRequired)
            throws TransactionTooLargeException {
            ...
            realStartServiceLocked(r, app, execInFg);
  ....
            }

該方法關鍵的就是執(zhí)行realStartServiceLocked(r, app, execInFg);其他沒什么好分析的 ,繼續(xù)跟進:

private final void realStartServiceLocked(ServiceRecord r,
            ProcessRecord app, boolean execInFg) throws RemoteException {
        if (app.thread == null) {
            throw new RemoteException();
        }
       
        r.setProcess(app);
      ...

        boolean created = false;
        try {
            //關鍵點1 : 開始回調(diào)調(diào)用者進程,熟悉的調(diào)用方式
            app.thread.scheduleCreateService(r, r.serviceInfo,
                    mAm.compatibilityInfoForPackage(r.serviceInfo.applicationInfo),
                    app.getReportedProcState());
            r.postNotification();
            created = true;
        } catch (DeadObjectException e) {
            Slog.w(TAG, "Application dead when creating service " + r);
            mAm.appDiedLocked(app);
            throw e;
        } finally {
           ...
        }
                ...

          //關鍵點 2
        requestServiceBindingsLocked(r, execInFg);

        updateServiceClientActivitiesLocked(app, null, true);
        ...
    }

看到關鍵點1 有沒有熟悉的感覺,沒錯就是跟activity啟動流程類似的調(diào)用,該方法的執(zhí)行會到ActivityThread執(zhí)行service的啟動,同理,注意相關參數(shù)

r:ServiceRecord,service的記錄,后續(xù)會通過該對象作為key保存啟動的Service

跨進程到了調(diào)用者進程,找到ActivityThread,跟進如下:

public final void scheduleCreateService(IBinder token,
        ServiceInfo info, CompatibilityInfo compatInfo, int processState) {
    updateProcessState(processState, false);
    CreateServiceData s = new CreateServiceData();
    s.token = token;
    s.info = info;
    s.compatInfo = compatInfo;

    sendMessage(H.CREATE_SERVICE, s);
}

包裝一個CreateServiceData,發(fā)送一個message ,進入主線程調(diào)用,最終到:

private void handleCreateService(CreateServiceData data) {
   
    LoadedApk packageInfo = getPackageInfoNoCheck(
            data.info.applicationInfo, data.compatInfo);
    Service service = null;
    try {
        java.lang.ClassLoader cl = packageInfo.getClassLoader();
      //反射方式創(chuàng)建一個service對象
        service = packageInfo.getAppFactory()
                .instantiateService(cl, data.info.name, data.intent);
    } catch (Exception e) {
        if (!mInstrumentation.onException(service, e)) {
            throw new RuntimeException(
                "Unable to instantiate service " + data.info.name
                + ": " + e.toString(), e);
        }
    }

    try {
                // 創(chuàng)建了一個context 對象,本質(zhì)上一個service對應一個context
        ContextImpl context = ContextImpl.createAppContext(this, packageInfo);
        context.setOuterContext(service);

        Application app = packageInfo.makeApplication(false, mInstrumentation);
        service.attach(context, this, data.info.name, data.token, app,
                ActivityManager.getService());
      // 關鍵點1 執(zhí)行service的oncreate 生命周期
        service.onCreate();
        mServices.put(data.token, service);
        try {
          // 關鍵點2 繼續(xù)跨進程到AMS 繼續(xù)執(zhí)行后續(xù)操作
            ActivityManager.getService().serviceDoneExecuting(
                    data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0);
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    } catch (Exception e) {
        if (!mInstrumentation.onException(service, e)) {
            throw new RuntimeException(
                "Unable to create service " + data.info.name
                + ": " + e.toString(), e);
        }
    }
}

從關鍵點1看出我們的service的生命周期開始執(zhí)行了,關鍵點2,又開始了跨進程之旅,到這我門的bind操作還沒真正執(zhí)行,目前只是start service了,好繼續(xù)serviceDoneExecuting的跟蹤,其實serviceDoneExecuting的執(zhí)行很簡單,就是沒有做任何有用的操作,這地方有興趣的自己可以跟蹤過去,注意對照SERVICE_DONE_EXECUTING_ANON參數(shù)看。
我們回到上面的realStartServiceLocked方法,繼續(xù)看下面的關鍵點2的執(zhí)行,發(fā)現(xiàn)執(zhí)行完啟動過程,會緊跟著執(zhí)行requestServiceBindingsLocked方法,這個又是做什么的,源碼如下:

private final boolean requestServiceBindingLocked(ServiceRecord r, IntentBindRecord i,
            boolean execInFg, boolean rebind) throws TransactionTooLargeException {
        if (r.app == null || r.app.thread == null) {
            // If service is not currently running, can't yet bind.
            return false;
        }
        
        if ((!i.requested || rebind) && i.apps.size() > 0) {
            try {
                bumpServiceExecutingLocked(r, execInFg, "bind");
                r.app.forceProcessStateUpTo(ActivityManager.PROCESS_STATE_SERVICE); 
              // 關鍵點1 ,熟悉的調(diào)用方式
                r.app.thread.scheduleBindService(r, i.intent.getIntent(), rebind,
                        r.app.getReportedProcState());
                if (!rebind) {
                    i.requested = true;
                }
                i.hasBound = true;
                i.doRebind = false;
            } catch (TransactionTooLargeException e) {
                // Keep the executeNesting count accurate.
                if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "Crashed while binding " + r, e);
                final boolean inDestroying = mDestroyingServices.contains(r);
                serviceDoneExecutingLocked(r, inDestroying, inDestroying);
                throw e;
            } catch (RemoteException e) {
                if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "Crashed while binding " + r);
                // Keep the executeNesting count accurate.
                final boolean inDestroying = mDestroyingServices.contains(r);
                serviceDoneExecutingLocked(r, inDestroying, inDestroying);
                return false;
            }
        }
        return true;
    }

看到在關鍵點1處,又跨進程執(zhí)行了ActivityThread的scheduleBindService方法,從名字也可猜出執(zhí)行到了我們的bind操作,nice,繼續(xù)看ActivityThread的執(zhí)行過程,最終經(jīng)過 handler 回調(diào)到 handleBindService:

private void handleBindService(BindServiceData data) {
    Service s = mServices.get(data.token);
   
    if (s != null) {
           ...
                if (!data.rebind) {
                  //關鍵點1 終于到了我們的onbind
                    IBinder binder = s.onBind(data.intent);
                  //關鍵點2 再一次跨進程到AMS
                    ActivityManager.getService().publishService(
                            data.token, data.intent, binder);
                } else {
                    s.onRebind(data.intent);
                    ActivityManager.getService().serviceDoneExecuting(
                            data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0);
                }
        ...
    }
}

關鍵點1 終于到了我們的onbind方法,還記得我們service中onbind會返回bind對象,然后關鍵點2處又開始將我們返回的binder對象傳遞到AMS ,那么繼續(xù)跟進去看看 :

void publishServiceLocked(ServiceRecord r, Intent intent, IBinder service) {
  ...
    ConnectionRecord c = clist.get(i);
    // conn :IServiceConnectio  service: 對應上面的返回的binder
     c.conn.connected(r.name, service, false);
    ...
}

該方法做了精簡主要的地方就是調(diào)用了connected方法,conn還記得開始分析的IServiceConnection嗎,沒錯,就是我們執(zhí)行bindServiceCommon方法中的sd對象(忘了的翻到上面的bindServiceCommon方法看看就知道了),我們看看這個對象怎么生成的,
很簡單跟蹤源碼可以看到就是new ServiceDispatcher(c, context, executor, flags)的操作,對應的構(gòu)造函數(shù)

ServiceDispatcher(ServiceConnection conn,
        Context context, Executor activityExecutor, int flags) {
    mIServiceConnection = new InnerConnection(this);
    mConnection = conn;
    mContext = context;
    mActivityThread = null;
    mActivityExecutor = activityExecutor;
    mLocation = new ServiceConnectionLeaked(null);
    mLocation.fillInStackTrace();
    mFlags = flags;
}

回到上面的c.conn.connected(r.name, service, false); 就是ServiceDispatcher的connected(r.name, service, false),這個方法如下:

public void connected(ComponentName name, IBinder service, boolean dead) {
    if (mActivityExecutor != null) {
        mActivityExecutor.execute(new RunConnection(name, service, 0, dead));
    } else if (mActivityThread != null) {
      //執(zhí)行到這,畢竟 ActivityThread 是存在的,service:對應上面的返回的binder
        mActivityThread.post(new RunConnection(name, service, 0, dead));
    } else {
        doConnected(name, service, dead);
    }
}

這地方post了一個runnable對象,就是執(zhí)行到了相關的run方法,在run方法中會調(diào)用到我們的onServiceConnected(name, service);

public void doConnected(ComponentName name, IBinder service, boolean dead) {
    ServiceDispatcher.ConnectionInfo old;
    ServiceDispatcher.ConnectionInfo info;

    synchronized (this) {
       ...
    // 關鍵點1 終于執(zhí)行了onServiceConnected 
    if (service != null) {
        mConnection.onServiceConnected(name, service);
    } else {
        // The binding machinery worked, but the remote returned null from onBind().
        mConnection.onNullBinding(name);
    }
   }
}

就是我們自己寫的MyConnection中的onServiceConnected,這地方的service參數(shù)就是service的onbind方法返回的binder對象,到此跟蹤了整個service的bind過程,bindService方式的源碼分析也就結(jié)束了。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

友情鏈接更多精彩內(nèi)容