Binder進(jìn)程間通信-JAVA層

進(jìn)程間通信基本原理

進(jìn)程間通信原理

Binder是什么帮非?

IPC(Inter-Process Communication 進(jìn)程間通信)通信機(jī)制

什么時候需要用到進(jìn)程間通信刮便?

WebView訪問,圖片加載(下載)蓄诽,推送薛训,雙進(jìn)程守護(hù)

系統(tǒng)進(jìn)程(獲取輸入法服務(wù),鬧鐘服務(wù)仑氛,攝相頭服務(wù)乙埃,電話等)

為什么要多進(jìn)程?

每個進(jìn)程的內(nèi)存是有限制的锯岖,在主進(jìn)程中進(jìn)行圖片加載介袜、下載內(nèi)存容易耗盡產(chǎn)生OOM, 而且下載機(jī)制很容易出錯出吹,出錯也會影響主進(jìn)程遇伞。

進(jìn)程間通信為什么要用到Binder機(jī)制?

內(nèi)存劃分
內(nèi)存劃分.png

進(jìn)程間的用戶空間是進(jìn)程隔離的趋箩,內(nèi)核空間是共享空間赃额。一般32位系統(tǒng)加派, 內(nèi)核空間為1G叫确,用戶空間為3G。一個進(jìn)程空間4G芍锦。

用戶空間可以通過內(nèi)核空間進(jìn)行訪問竹勉。

Binder的作用和使用場景

Binder作用就是來實(shí)現(xiàn)進(jìn)程之間通過內(nèi)核空間實(shí)現(xiàn)通信的。

安卓增加Binder的原因

Binder與傳統(tǒng)IPC對比

Binder 共享內(nèi)存 Socket
性能 需要拷貝一次 無需拷貝 需要拷貝兩次
特點(diǎn) 基于C/S 架構(gòu) 易用性高 控制復(fù)雜娄琉,易用性差 基于C/S 架構(gòu) 作為一款通用接口次乓,其傳輸效率低,開銷大
安全性 為每個APP分配UID 同時支持實(shí)名和匿名 依賴上層協(xié)議 訪問接入點(diǎn)是開放的 不安全 依賴上層協(xié)議 訪問接入點(diǎn)是開放的 不安全

性能

Binder只需要拷貝一次孽水;共享內(nèi)存無需拷貝票腰;Socket需要拷貝兩次

特點(diǎn)

Binder基于C/S架構(gòu),易用性高女气;共享內(nèi)存控制復(fù)雜杏慰,易用性差;Socket基于C/S架構(gòu)作為一款通用接口,傳輸效率低缘滥,開銷大

安全性

Binder 為每個APP分配 UID同時支持實(shí)名和匿名轰胁;共享內(nèi)存依賴上層協(xié)議,訪問接入點(diǎn)是開放的朝扼,不安全赃阀;Socket 依賴上層協(xié)議,訪問接入點(diǎn)是開放的擎颖,不安全

傳統(tǒng) IPC 傳輸數(shù)據(jù)

傳統(tǒng)IPC.png
  1. 用戶空間發(fā)送數(shù)據(jù)
  2. 通過系統(tǒng)調(diào)用copy_from_user()將數(shù)據(jù)從用戶空間copy到內(nèi)核緩存區(qū)(第1次copy)
  3. 另一個進(jìn)程中:通過調(diào)用copy_from_user()將數(shù)據(jù)從內(nèi)核緩存空間copy到用戶空間(第2次copy)
  4. 接收數(shù)據(jù)

Binder 傳輸數(shù)據(jù)

Binder傳輸.png
  1. 用戶空間發(fā)送數(shù)據(jù)
  2. 通過系統(tǒng)調(diào)用copy_from_user()將數(shù)據(jù)從用戶空間copy到內(nèi)核緩存區(qū)
  3. 因?yàn)榇嬖谟成潢P(guān)系(mmap內(nèi)存映射將一個文件或者其它對象映射進(jìn)內(nèi)存)榛斯,所以實(shí)現(xiàn)了跨進(jìn)程通信

(內(nèi)核緩存區(qū)和S端(接收端)的數(shù)據(jù)接收緩存區(qū) 映射同一塊物理空間)

Binder源碼分析

AIDL

AIDL: (Android Interface Definition Language) Android接口定義語言

每個服務(wù)都有個aidl與之對應(yīng)。

Proxy:發(fā)送數(shù)據(jù)(客戶端)

Stub:接收數(shù)據(jù)(服務(wù)端)

aidl.png

客戶端:

在ServiceConnection中

獲取aidl對象的方法(XXXAidl是定義的AIDL)

XXXAidl.Stub.asInterface(service);

asInterface跳轉(zhuǎn)到了Stub中的asInterface方法

Stub繼承了Binder并實(shí)現(xiàn)了aidl接口

public static abstract class Stub extends android.os.Binder implements com.lis.binder_learn.Aidl {
    private static final java.lang.String DESCRIPTOR = "com.lis.binder_learn.Aidl";

    /**
     * Construct the stub at attach it to the interface.
     */
    public Stub() {
        this.attachInterface(this, DESCRIPTOR);
    }

    /**
     * Cast an IBinder object into an com.lis.binder_learn.Aidl interface,
     * generating a proxy if needed.
     */
    public static com.lis.binder_learn.Aidl asInterface(android.os.IBinder obj) {
        if ((obj == null)) {
            return null;
        }
        android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
        if (((iin != null) && (iin instanceof com.lis.binder_learn.Aidl))) {
            return ((com.lis.binder_learn.Aidl) iin);
        }
        return new com.lis.binder_learn.Aidl.Stub.Proxy(obj);
    }

    @Override
    public android.os.IBinder asBinder() {
        return this;
    }

    @Override
    public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException {
        java.lang.String descriptor = DESCRIPTOR;
        switch (code) {
            case INTERFACE_TRANSACTION: {
                reply.writeString(descriptor);
                return true;
            }
            case TRANSACTION_addPerson: {
                data.enforceInterface(descriptor);
                com.lis.binder_learn.Person _arg0;
                if ((0 != data.readInt())) {
                    _arg0 = com.lis.binder_learn.Person.CREATOR.createFromParcel(data);
                } else {
                    _arg0 = null;
                }
                this.addPerson(_arg0);
                reply.writeNoException();
                return true;
            }
            case TRANSACTION_getPersonList: {
                data.enforceInterface(descriptor);
                java.util.List<com.lis.binder_learn.Person> _result = this.getPersonList();
                reply.writeNoException();
                reply.writeTypedList(_result);
                return true;
            }
            default: {
                return super.onTransact(code, data, reply, flags);
            }
        }
    }

asInterface方法中queryLocalInterface是Binder.java中實(shí)現(xiàn)

public @Nullable IInterface queryLocalInterface(@NonNull String descriptor) {
        if (mDescriptor != null && mDescriptor.equals(descriptor)) {
            return mOwner;
        }
        return null;
    }

在Stub的構(gòu)造方法中,將自身和DESCRIPTOR(com.lis.binder_learn.Aidl 全類名)傳到了Binder.java中

public Stub() {
    this.attachInterface(this, DESCRIPTOR);
}
public void attachInterface(@Nullable IInterface owner, @Nullable String descriptor) {
    mOwner = owner;
    mDescriptor = descriptor;
}

所以queryLocalInterface方法是查詢保存到本地的descriptor是否相等搂捧,相等就返回了自身Aidl

但是客戶端這里是不相等的肖抱,因?yàn)榭头藳]有調(diào)用Stub的構(gòu)造承當(dāng),這里的傳入的descriptor是個空异旧。

(這一塊是在服務(wù)端進(jìn)行傳入的Stub)

客服端不會始化Stub不傳descriptor意述,服務(wù)端會初始化Stub傳descriptor。

這里的查詢比較是因?yàn)椋?/strong>Activity和Service有可能是同一進(jìn)程當(dāng)中的吮蛹,如果是同一進(jìn)程就不需要進(jìn)行binder進(jìn)行傳輸了荤崇。

if (((iin != null) && (iin instanceof com.lis.binder_learn.Aidl))) {
    return ((com.lis.binder_learn.Aidl) iin);
}
return new com.lis.binder_learn.Aidl.Stub.Proxy(obj);

這里如果是同一進(jìn)程就直接返回aidl,如果不是同一進(jìn)程就返回了Proxy。

mAidl = Aidl.Stub.asInterface(service);

這里客戶端就拿到了proxy(mAidl)

mAidl.addPerson(new Person("張三", 1));

調(diào)用mAidl的方法潮针,就進(jìn)了Proxy中的方法中

Proxy是個實(shí)體類實(shí)現(xiàn)了aidl接口

private static class Proxy implements com.lis.binder_learn.Aidl {
    private android.os.IBinder mRemote;

    Proxy(android.os.IBinder remote) {
        mRemote = remote;
    }

    @Override
    public android.os.IBinder asBinder() {
        return mRemote;
    }

    public java.lang.String getInterfaceDescriptor() {
        return DESCRIPTOR;
    }
    //客戶端傳輸

    @Override
    public void addPerson(com.lis.binder_learn.Person person) throws android.os.RemoteException {
        android.os.Parcel _data = android.os.Parcel.obtain();
        android.os.Parcel _reply = android.os.Parcel.obtain();
        try {
            _data.writeInterfaceToken(DESCRIPTOR);
            if ((person != null)) {
                _data.writeInt(1);
                person.writeToParcel(_data, 0);
            } else {
                _data.writeInt(0);
            }
            boolean _status = mRemote.transact(Stub.TRANSACTION_addPerson, _data, _reply, 0);
            if (!_status && getDefaultImpl() != null) {
                getDefaultImpl().addPerson(person);
                return;
            }
            _reply.readException();
        } finally {
            _reply.recycle();
            _data.recycle();
        }
    }

    @Override
    public java.util.List<com.lis.binder_learn.Person> getPersonList() throws android.os.RemoteException {
        android.os.Parcel _data = android.os.Parcel.obtain();
        android.os.Parcel _reply = android.os.Parcel.obtain();
        java.util.List<com.lis.binder_learn.Person> _result;
        try {
            _data.writeInterfaceToken(DESCRIPTOR);
            boolean _status = mRemote.transact(Stub.TRANSACTION_getPersonList, _data, _reply, 0);
            if (!_status && getDefaultImpl() != null) {
                return getDefaultImpl().getPersonList();
            }
            _reply.readException();
            _result = _reply.createTypedArrayList(com.lis.binder_learn.Person.CREATOR);
        } finally {
            _reply.recycle();
            _data.recycle();
        }
        return _result;
    }

    public static com.lis.binder_learn.Aidl sDefaultImpl;
}

_data就是發(fā)送到服務(wù)端的數(shù)據(jù)

_reply就是服務(wù)端返回的數(shù)據(jù)

@Override
public void addPerson(com.lis.binder_learn.Person person) throws android.os.RemoteException {
    android.os.Parcel _data = android.os.Parcel.obtain();
    android.os.Parcel _reply = android.os.Parcel.obtain();
    try {
        _data.writeInterfaceToken(DESCRIPTOR);
        if ((person != null)) {
            _data.writeInt(1);
            person.writeToParcel(_data, 0);
        } else {
            _data.writeInt(0);
        }
        boolean _status = mRemote.transact(Stub.TRANSACTION_addPerson, _data, _reply, 0);
        if (!_status && getDefaultImpl() != null) {
            getDefaultImpl().addPerson(person);
            return;
        }
        _reply.readException();
    } finally {
        _reply.recycle();
        _data.recycle();
    }
}

這里做了個數(shù)據(jù)的校驗(yàn)

_data.writeInterfaceToken(DESCRIPTOR);

通過mRemote.transact方法术荤,將數(shù)據(jù)發(fā)送給服務(wù)端,這時客戶端線程掛起每篷,直到服務(wù)端數(shù)據(jù)返回瓣戚。這里的flags=0表示,客戶端和服務(wù)端可以想到通信焦读,1的話代表客戶端發(fā)到服務(wù)端子库,服務(wù)端不能返回。

Stub.TRANSACTION_addPerson:因?yàn)榭蛻舳撕头?wù)端的AIDL是一樣的矗晃,所以方法順序是一樣的仑嗅。這里傳入方法順序數(shù),就可以知道調(diào)用的哪個方法(整型)

boolean _status = mRemote.transact(Stub.TRANSACTION_addPerson, _data, _reply, 0);

transact方法在Binder.java中张症,調(diào)用 onTransact

public final boolean transact(int code, @NonNull Parcel data, @Nullable Parcel reply,
        int flags) throws RemoteException {
    if (false) Log.v("Binder", "Transact: " + code + " to " + this);

    if (data != null) {
        data.setDataPosition(0);
    }
    boolean r = onTransact(code, data, reply, flags);
    if (reply != null) {
        reply.setDataPosition(0);
    }
    return r;
}

這里會到服務(wù)端的Stub#onTransact方法

服務(wù)端:

@Override
public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException {
    java.lang.String descriptor = DESCRIPTOR;
    switch (code) {
        case INTERFACE_TRANSACTION: {
            reply.writeString(descriptor);
            return true;
        }
        case TRANSACTION_addPerson: {
            data.enforceInterface(descriptor);
            com.lis.binder_learn.Person _arg0;
            if ((0 != data.readInt())) {
                _arg0 = com.lis.binder_learn.Person.CREATOR.createFromParcel(data);
            } else {
                _arg0 = null;
            }
            this.addPerson(_arg0);
            reply.writeNoException();
            return true;
        }
        case TRANSACTION_getPersonList: {
            data.enforceInterface(descriptor);
            java.util.List<com.lis.binder_learn.Person> _result = this.getPersonList();
            reply.writeNoException();
            reply.writeTypedList(_result);
            return true;
        }
        default: {
            return super.onTransact(code, data, reply, flags);
        }
    }
}

根據(jù)code 找到調(diào)用的哪個方法case TRANSACTION_addPerson

data.enforceInterface(descriptor);

這里根據(jù)descriptor進(jìn)行校驗(yàn)

this.addPerson(_arg0);

這里的addPerson調(diào)用的是Service中實(shí)現(xiàn)的Stub()中addPerson方法

private IBinder mIBinder = new Aidl.Stub() {
    @Override
    public void addPerson(Person person) throws RemoteException {

        persons.add(person);
        Log.e("AidlService", "persons.size: "+persons.size());
    }

    @Override
    public List<Person> getPersonList() throws RemoteException {
        Log.e("AidlService", "getPersonList.size: "+persons.size());
        return persons;
    }
};

AIDL時序圖:

時序圖.png

最后通過_reply進(jìn)行數(shù)據(jù)返回

如何獲得另一個進(jìn)程的對象

bindService中都 做了些什么仓技?

bindService(intent, mServiceConnection, Context.BIND_AUTO_CREATE);
@Override
public boolean bindService(Intent service, ServiceConnection conn,
        int flags) {
    return mBase.bindService(service, conn, flags);
}

最后調(diào)用了ContextImpl.bindService

@Override
public boolean bindService(Intent service, ServiceConnection conn, int flags) {
    warnIfCallingFromSystemProcess();
    return bindServiceCommon(service, conn, flags, null, mMainThread.getHandler(), null,
            getUser());
}

bindServiceCommon

private boolean bindServiceCommon(Intent service, ServiceConnection conn, int flags,
        String instanceName, Handler handler, Executor executor, UserHandle user) {
    // Keep this in sync with DevicePolicyManager.bindDeviceAdminServiceAsUser.
    IServiceConnection sd;
    if (conn == null) {
        throw new IllegalArgumentException("connection is null");
    }
    if (handler != null && executor != null) {
        throw new IllegalArgumentException("Handler and Executor both supplied");
    }
    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);
        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();
    }
}
 //基于23的代碼
 int res = ActivityManagerNative.getDefault().bindService(
                mMainThread.getApplicationThread(), getActivityToken(), service,
                service.resolveTypeIfNeeded(getContentResolver()),
                sd, flags, getOpPackageName(), user.getIdentifier());
static public IActivityManager getDefault() {
        return gDefault.get();
    }
public interface IActivityManager extends IInterface

IActivityManager繼承自IInterface

public interface IInterface
{
    /**
     * Retrieve the Binder object associated with this interface.
     * You must use this instead of a plain cast, so that proxy objects
     * can return the correct result.
     */
    public IBinder asBinder();
}

這樣,IActivityManager=AIDL接口

private static final Singleton<IActivityManager> gDefault = new Singleton<IActivityManager>() {
    protected IActivityManager create() {
        IBinder b = ServiceManager.getService("activity");
        if (false) {
            Log.v("ActivityManager", "default service binder = " + b);
        }
        IActivityManager am = asInterface(b);
        if (false) {
            Log.v("ActivityManager", "default service = " + am);
        }
        return am;
    }
};
IBinder b = ServiceManager.getService("activity");

這里ServiceManager把我們調(diào)用的服務(wù)的IBinder返回俗他。(這個IBinder就是AMS服務(wù))

IActivityManager am = asInterface(b);

通過asInterface 返回 脖捻,這里的am就是Proxy

就是ActivityManagerNative.getDefault()這里返回一個Proxy對象

asInterface會跑到Stub中去

public abstract class ActivityManagerNative extends Binder implements IActivityManager
{
    /**
     * Cast a Binder object into an activity manager interface, generating
     * a proxy if needed.
     */
    static public IActivityManager asInterface(IBinder obj) {
        if (obj == null) {
            return null;
        }
        IActivityManager in =
            (IActivityManager)obj.queryLocalInterface(descriptor);
        if (in != null) {
            return in;
        }

        return new ActivityManagerProxy(obj);
    }
    ...

所以ActivityManagerNative 就是Stub

即:ActivityManagerNative== Stub

ActivityManagerNative$ActivityManagerProxy == Proxy

ActivityManagerProxy #bindService

public int bindService(IApplicationThread caller, IBinder token,
        Intent service, String resolvedType, IServiceConnection connection,
        int flags,  String callingPackage, int userId) throws RemoteException {
    Parcel data = Parcel.obtain();
    Parcel reply = Parcel.obtain();
    data.writeInterfaceToken(IActivityManager.descriptor);
    data.writeStrongBinder(caller != null ? caller.asBinder() : null);
    data.writeStrongBinder(token);
    service.writeToParcel(data, 0);
    data.writeString(resolvedType);
    data.writeStrongBinder(connection.asBinder());
    data.writeInt(flags);
    data.writeString(callingPackage);
    data.writeInt(userId);
    mRemote.transact(BIND_SERVICE_TRANSACTION, data, reply, 0);
    reply.readException();
    int res = reply.readInt();
    data.recycle();
    reply.recycle();
    return res;
}

mRemote.transact(BIND_SERVICE_TRANSACTION, data, reply, 0); 跳到ActivityManagerNative#onTransact方法

case BIND_SERVICE_TRANSACTION: {
    data.enforceInterface(IActivityManager.descriptor);
    IBinder b = data.readStrongBinder();
    IApplicationThread app = ApplicationThreadNative.asInterface(b);
    IBinder token = data.readStrongBinder();
    Intent service = Intent.CREATOR.createFromParcel(data);
    String resolvedType = data.readString();
    b = data.readStrongBinder();
    int fl = data.readInt();
    String callingPackage = data.readString();
    int userId = data.readInt();
    IServiceConnection conn = IServiceConnection.Stub.asInterface(b);
    int res = bindService(app, token, service, resolvedType, conn, fl,
            callingPackage, userId);
    reply.writeNoException();
    reply.writeInt(res);
    return true;
}

bindService(app, token, service, resolvedType, conn, fl,callingPackage, userId); 這里的bindService是調(diào)用的真正的服務(wù)Service(這里使用的AMS服務(wù))

public final class ActivityManagerService extends ActivityManagerNative

ActivityManagerService#bindService ====>ActivityManagerService#bindServiceLocked

  1. ActivityServices#bringUpServiceLocked()

    進(jìn)程狀態(tài)的1,2

  2. ActivityServices#requestServiceBindingLocked(s, b.intent, callerFg, true);

    進(jìn)程狀態(tài)的3兆衅,4

A進(jìn)程訪問B進(jìn)程時的幾種狀態(tài)

進(jìn)程的幾種狀態(tài).png

bringUpServiceLocked()

2. app存在地沮,但是Service沒創(chuàng)建
if (!isolated) {
            app = mAm.getProcessRecordLocked(procName, r.appInfo.uid, false);
            if (DEBUG_MU) Slog.v(TAG_MU, "bringUpServiceLocked: appInfo.uid=" + r.appInfo.uid
                        + " app=" + app);
            if (app != null && app.thread != null) {
                try {
                    app.addPackage(r.appInfo.packageName, r.appInfo.versionCode, mAm.mProcessStats);
                    realStartServiceLocked(r, app, execInFg);
                    return null;
                } catch (TransactionTooLargeException e) {
                    throw e;
                } catch (RemoteException e) {
                    Slog.w(TAG, "Exception when starting service " + r.shortName, e);
                }

                // If a dead object exception was thrown -- fall through to
                // restart the application.
            }
        } 

app創(chuàng)建了

if (app != null && app.thread != null) ` 代表B進(jìn)程已經(jīng)啟動

realStartServiceLocked(r, app, execInFg); 啟動服務(wù)

realStartServiceLocked中

app.thread.scheduleCreateService(r, r.serviceInfo,
        mAm.compatibilityInfoForPackageLocked(r.serviceInfo.applicationInfo),
        app.repProcState);

這里的app是應(yīng)用進(jìn)程颜价,thread是ApplicationThread(ActivityThread#ApplicationThread)

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);
}

進(jìn)到了Handler

case CREATE_SERVICE:
    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "serviceCreate");
    handleCreateService((CreateServiceData)msg.obj);
    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
    break;

創(chuàng)建服務(wù)的方法handleCreateService

private void handleCreateService(CreateServiceData data) {
    // If we are getting ready to gc after going to the background, well
    // we are back active so skip it.
    unscheduleGcIdler();

    LoadedApk packageInfo = getPackageInfoNoCheck(
            data.info.applicationInfo, data.compatInfo);
    Service service = null;
    try {
        java.lang.ClassLoader cl = packageInfo.getClassLoader();
        service = (Service) cl.loadClass(data.info.name).newInstance();
    } catch (Exception e) {
        if (!mInstrumentation.onException(service, e)) {
            throw new RuntimeException(
                "Unable to instantiate service " + data.info.name
                + ": " + e.toString(), e);
        }
    }

    try {
        if (localLOGV) Slog.v(TAG, "Creating service " + data.info.name);

        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,
                ActivityManagerNative.getDefault());
        service.onCreate();
        mServices.put(data.token, service);
        try {
            ActivityManagerNative.getDefault().serviceDoneExecuting(
                    data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0);
        } catch (RemoteException e) {
            // nothing to do.
        }
    } catch (Exception e) {
        if (!mInstrumentation.onException(service, e)) {
            throw new RuntimeException(
                "Unable to create service " + data.info.name
                + ": " + e.toString(), e);
        }
    }
}

service = (Service) cl.loadClass(data.info.name).newInstance();--->AidlService 創(chuàng)建了我們的服務(wù)(通過類加載器,反射創(chuàng)建)

調(diào)用service生命周期诉濒,保存服務(wù)

service.attach(context, this, data.info.name, data.token, app,
        ActivityManagerNative.getDefault());
service.onCreate();
mServices.put(data.token, service);
1. 進(jìn)程沒有啟動

app沒有創(chuàng)建

if (app == null) {
    if ((app=mAm.startProcessLocked(procName, r.appInfo, true, intentFlags,
            "service", r.name, false, isolated, false)) == null) {
        String msg = "Unable to launch app "
                + r.appInfo.packageName + "/"
                + r.appInfo.uid + " for service "
                + r.intent.getIntent() + ": process is bad";
        Slog.w(TAG, msg);
        bringDownServiceLocked(r);
        return msg;
    }
    if (isolated) {
        r.isolatedProc = app;
    }
}

進(jìn)入到startProcessLocked中的

Process.ProcessStartResult startResult = Process.start(entryPoint,
        app.processName, uid, uid, gids, debugFlags, mountExternal,
        app.info.targetSdkVersion, app.info.seinfo, requiredAbi, instructionSet,
        app.info.dataDir, entryPointArgs);

創(chuàng)建進(jìn)程

requestServiceBindingLocked

綁定服務(wù):

requestServiceBindingLocked(ServiceRecord r, IntentBindRecord i,
        boolean execInFg, boolean rebind)

綁定與否 和rebind有關(guān)周伦,走的同一個方法

try {
    bumpServiceExecutingLocked(r, execInFg, "bind");
    r.app.forceProcessStateUpTo(ActivityManager.PROCESS_STATE_SERVICE);
    r.app.thread.scheduleBindService(r, i.intent.getIntent(), rebind,
            r.app.repProcState);
    if (!rebind) {
        i.requested = true;
    }
    i.hasBound = true;
    i.doRebind = false;
}

調(diào)用scheduleBindService方法==》ActivityThread#scheduleBindService

public final void scheduleBindService(IBinder token, Intent intent,
        boolean rebind, int processState) {
    updateProcessState(processState, false);
    BindServiceData s = new BindServiceData();
    s.token = token;
    s.intent = intent;
    s.rebind = rebind;

    if (DEBUG_SERVICE)
        Slog.v(TAG, "scheduleBindService token=" + token + " intent=" + intent + " uid="
                + Binder.getCallingUid() + " pid=" + Binder.getCallingPid());
    sendMessage(H.BIND_SERVICE, s);
}
case BIND_SERVICE:
    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "serviceBind");
    handleBindService((BindServiceData)msg.obj);
    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
    break;
private void handleBindService(BindServiceData data) {
    Service s = mServices.get(data.token);
    if (DEBUG_SERVICE)
        Slog.v(TAG, "handleBindService s=" + s + " rebind=" + data.rebind);
    if (s != null) {
        try {
            data.intent.setExtrasClassLoader(s.getClassLoader());
            data.intent.prepareToEnterProcess();
            try {
                if (!data.rebind) {
                    IBinder binder = s.onBind(data.intent);
                    ActivityManagerNative.getDefault().publishService(
                            data.token, data.intent, binder);
                } else {
                    s.onRebind(data.intent);
                    ActivityManagerNative.getDefault().serviceDoneExecuting(
                            data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0);
                }
                ensureJitEnabled();
            } catch (RemoteException ex) {
            }
        } catch (Exception e) {
            if (!mInstrumentation.onException(s, e)) {
                throw new RuntimeException(
                        "Unable to bind to service " + s
                        + " with " + data.intent + ": " + e.toString(), e);
            }
        }
    }
}
IBinder binder = s.onBind(data.intent);

binder是調(diào)用的是AidlService中的onBind()返回的binder

public class AidlService extends Service {
    private ArrayList<Person> persons;

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        persons = new ArrayList<>();
        Log.e("AidlService", "success onBind");
        return mIBinder;
    }
    ...
    }
ActivityManagerNative.getDefault().publishService(
        data.token, data.intent, binder);

ActivityManagerNative.getDefault()==>Proxy==>AMS中的publishService

ActivityManagerService#publishService

public void publishService(IBinder token, Intent intent, IBinder service) {
    // Refuse possible leaked file descriptors
    if (intent != null && intent.hasFileDescriptors() == true) {
        throw new IllegalArgumentException("File descriptors passed in Intent");
    }

    synchronized(this) {
        if (!(token instanceof ServiceRecord)) {
            throw new IllegalArgumentException("Invalid service token");
        }
        mServices.publishServiceLocked((ServiceRecord)token, intent, service);
    }
}

mServices.publishServiceLocked((ServiceRecord)token, intent, service);

publishServiceLocked中

try {
    c.conn.connected(r.name, service);
} catch (Exception e) {
    Slog.w(TAG, "Failure sending service " + r.name +
          " to connection " + c.conn.asBinder() +
          " (in " + c.binding.client.processName + ")", e);
}

c.conn.connected(r.name, service);==>調(diào)用到客戶端的onServiceConnected()

參數(shù)就是服務(wù)端的IBinder

ConnectionRecord c

IServiceConnection conn

客戶端:

bindService(intent, mServiceConnection, Context.BIND_AUTO_CREATE);

bindService時傳入了ServiceConnection-->ContextImp#bindServiceCommon

IServiceConnection sd;
if (mPackageInfo != null) {
    sd = mPackageInfo.getServiceDispatcher(conn, getOuterContext(),
            mMainThread.getHandler(), flags);
}

這里傳入了conn

public final IServiceConnection getServiceDispatcher(ServiceConnection c,
        Context context, Handler handler, int flags) {
    synchronized (mServices) {
        LoadedApk.ServiceDispatcher sd = null;
        ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher> map = mServices.get(context);
        if (map != null) {
            sd = map.get(c);
        }
        if (sd == null) {
            sd = new ServiceDispatcher(c, context, handler, flags);
            if (map == null) {
                map = new ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher>();
                mServices.put(context, map);
            }
            map.put(c, sd);
        } else {
            sd.validate(context, handler);
        }
        return sd.getIServiceConnection();
    }
}

sd = new ServiceDispatcher(c, context, handler, flags);

這里傳入了ServiceConnection,最后從sd.getIServiceConnection() 返回IServiceConnection

IServiceConnection getIServiceConnection() {
    return mIServiceConnection;
}
private final ServiceDispatcher.InnerConnection mIServiceConnection;

這里返回的是個InnerConnection對象

private static class InnerConnection extends IServiceConnection.Stub {
    final WeakReference<LoadedApk.ServiceDispatcher> mDispatcher;

    InnerConnection(LoadedApk.ServiceDispatcher sd) {
        mDispatcher = new WeakReference<LoadedApk.ServiceDispatcher>(sd);
    }

    public void connected(ComponentName name, IBinder service) throws RemoteException {
        LoadedApk.ServiceDispatcher sd = mDispatcher.get();
        if (sd != null) {
            sd.connected(name, service);
        }
    }
}

上面的c.conn.connected就是調(diào)用的InnerConnection#connected方法未荒,

而這個方法又調(diào)用了sd.connected

public void connected(ComponentName name, IBinder service) {
    if (mActivityThread != null) {
        mActivityThread.post(new RunConnection(name, service, 0));
    } else {
        doConnected(name, service);
    }
}
public void doConnected(ComponentName name, IBinder service) {
    ServiceDispatcher.ConnectionInfo old;
    ServiceDispatcher.ConnectionInfo info;

    synchronized (this) {
        if (mForgotten) {
            // We unbound before receiving the connection; ignore
            // any connection received.
            return;
        }
        old = mActiveConnections.get(name);
        if (old != null && old.binder == service) {
            // Huh, already have this one.  Oh well!
            return;
        }

        if (service != null) {
            // A new service is being connected... set it all up.
            mDied = false;
            info = new ConnectionInfo();
            info.binder = service;
            info.deathMonitor = new DeathMonitor(name, service);
            try {
                service.linkToDeath(info.deathMonitor, 0);
                mActiveConnections.put(name, info);
            } catch (RemoteException e) {
                // This service was dead before we got it...  just
                // don't do anything with it.
                mActiveConnections.remove(name);
                return;
            }

        } else {
            // The named service is being disconnected... clean up.
            mActiveConnections.remove(name);
        }

        if (old != null) {
            old.binder.unlinkToDeath(old.deathMonitor, 0);
        }
    }

    // If there was an old service, it is not disconnected.
    if (old != null) {
        mConnection.onServiceDisconnected(name);
    }
    // If there is a new service, it is now connected.
    if (service != null) {
        mConnection.onServiceConnected(name, service);
    }
}
// If there was an old service, it is not disconnected.
if (old != null) {
    mConnection.onServiceDisconnected(name);
}
// If there is a new service, it is now connected.
if (service != null) {
    mConnection.onServiceConnected(name, service);
}

這里就調(diào)到了connection的方法专挪。

所以上面c.conn.connected(r.name, service)就是調(diào)用的ServiceConnection的onServiceConnected方法。

如何進(jìn)行通信的

總結(jié)

總結(jié).png

PS:進(jìn)程知識補(bǔ)充

進(jìn)程分為:

  • 前臺進(jìn)程
  • 可見進(jìn)程
  • 服務(wù)進(jìn)程
  • 后臺進(jìn)程
  • 空進(jìn)程
進(jìn)程.png

前臺進(jìn)程:

有一個Activity

  • ? 正在交互

有一個Service

  • 綁定到正在交互的Activity
  • “前臺運(yùn)行”片排,startForeground()
  • 正在執(zhí)行生命周期回調(diào)onCreate()

有一個BroadcastReceiver

  • 正在執(zhí)行onReceive()

可見進(jìn)程:

有一個Activity

  • 不在交互寨腔,但仍可見

有一個Service

  • 綁定到可見Activity

服務(wù)進(jìn)程:

  • 普通Service

故而對耗時的比如上傳等,新建一個Service比在Activity新建一個線程好的多率寡。

后臺進(jìn)程:

  • 所有Activity都對用戶不可見

會被保存在LRU列表中迫卢,即最近查看的最晚被終止

空進(jìn)程:

系統(tǒng)有時候會使用空進(jìn)程做為緩存,以縮短下一次在其中運(yùn)行組建所需的啟動時間

多進(jìn)程的特性

  • 不同的內(nèi)存空間冶共,數(shù)據(jù)無法共享
  • 需要謹(jǐn)慎處理代碼中的線程同步
  • 需要提防多進(jìn)程并發(fā)導(dǎo)致的文件鎖和數(shù)據(jù)庫鎖時效的問題

具體問題:

1. 靜態(tài)成員和單例模式完全失效
2. 線程同步機(jī)制失效
3. SharedPreferences可靠性下降
4. Application會多次重建

如何判斷進(jìn)程的優(yōu)先級

通過oom_adj 值乾蛤,判斷進(jìn)程的優(yōu)先級

不同手機(jī)的oom_adj 值 可能不一樣

進(jìn)程優(yōu)先級.png

進(jìn)程間通信方式

進(jìn)程間通信方式對比.png

線程間通信

  1. 共享內(nèi)存
  2. 文件、數(shù)據(jù)庫
  3. Handler
  4. Java里的wait notify notifyAll

在非UI線程中更新UI

  • Activity.runOnUiThread(Runnable)
  • View.post(Runnable)
  • View.postDelayed(Runnable,long)
  • handler
  • AsyncTask
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末捅僵,一起剝皮案震驚了整個濱河市家卖,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌庙楚,老刑警劉巖上荡,帶你破解...
    沈念sama閱讀 216,372評論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異馒闷,居然都是意外死亡酪捡,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,368評論 3 392
  • 文/潘曉璐 我一進(jìn)店門纳账,熙熙樓的掌柜王于貴愁眉苦臉地迎上來逛薇,“玉大人,你說我怎么就攤上這事塞祈〗鸬螅” “怎么了帅涂?”我有些...
    開封第一講書人閱讀 162,415評論 0 353
  • 文/不壞的土叔 我叫張陵议薪,是天一觀的道長。 經(jīng)常有香客問我媳友,道長斯议,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,157評論 1 292
  • 正文 為了忘掉前任醇锚,我火速辦了婚禮哼御,結(jié)果婚禮上坯临,老公的妹妹穿的比我還像新娘。我一直安慰自己恋昼,他們只是感情好看靠,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,171評論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著液肌,像睡著了一般挟炬。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上嗦哆,一...
    開封第一講書人閱讀 51,125評論 1 297
  • 那天谤祖,我揣著相機(jī)與錄音,去河邊找鬼老速。 笑死粥喜,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的橘券。 我是一名探鬼主播额湘,決...
    沈念sama閱讀 40,028評論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼旁舰!你這毒婦竟也來了缩挑?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,887評論 0 274
  • 序言:老撾萬榮一對情侶失蹤鬓梅,失蹤者是張志新(化名)和其女友劉穎供置,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體绽快,經(jīng)...
    沈念sama閱讀 45,310評論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡芥丧,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,533評論 2 332
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了坊罢。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片续担。...
    茶點(diǎn)故事閱讀 39,690評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖活孩,靈堂內(nèi)的尸體忽然破棺而出物遇,到底是詐尸還是另有隱情,我是刑警寧澤憾儒,帶...
    沈念sama閱讀 35,411評論 5 343
  • 正文 年R本政府宣布询兴,位于F島的核電站,受9級特大地震影響起趾,放射性物質(zhì)發(fā)生泄漏诗舰。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,004評論 3 325
  • 文/蒙蒙 一训裆、第九天 我趴在偏房一處隱蔽的房頂上張望眶根。 院中可真熱鬧蜀铲,春花似錦、人聲如沸属百。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽族扰。三九已至隆夯,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間别伏,已是汗流浹背蹄衷。 一陣腳步聲響...
    開封第一講書人閱讀 32,812評論 1 268
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留厘肮,地道東北人愧口。 一個月前我還...
    沈念sama閱讀 47,693評論 2 368
  • 正文 我出身青樓,卻偏偏與公主長得像类茂,于是被迫代替她去往敵國和親耍属。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,577評論 2 353