Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android的服務(Service)(三)Service客戶端的綁定與跨進程

Android的服務(Service)(三)Service客戶端的綁定與跨進程

編輯:關於Android編程

繼續上篇的分析,接下來是第三個問題”Service與其客戶端的綁定如何實現,即跨進程調用問題“

(一)、Service的生命周期

(二)、Service的自動重啟問題

(三)、Service與其客戶端的綁定如何實現,即跨進程調用問題。

服務於客戶端的綁定通過binder來實現的,就是客戶端去bind服務。來看看ContextImpl的bindServiceCommon方法

 

    private boolean bindServiceCommon(Intent service, ServiceConnection conn, int flags,
            UserHandle user) {
        IServiceConnection sd;
        if (mPackageInfo != null) {
            sd = mPackageInfo.getServiceDispatcher(conn, getOuterContext(),
                    mMainThread.getHandler(), flags);
        }
        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();
            int res = ActivityManagerNative.getDefault().bindService(
                mMainThread.getApplicationThread(), getActivityToken(),
                service, service.resolveTypeIfNeeded(getContentResolver()),
                sd, flags, user.getIdentifier());
            if (res < 0) {
                throw new SecurityException(
                        Not allowed to bind to service  + service);
            }
            return res != 0;
        }
    }
然後會去LoadedApk.java裡面會創建用於跨進程連接的binder對象,就是一個ServiceDispatcher的InnerConnection。
    public final IServiceConnection getServiceDispatcher(ServiceConnection c,
            Context context, Handler handler, int flags) {
        synchronized (mServices) {
            LoadedApk.ServiceDispatcher sd = null;
            //這裡用一個map將所有的連接記錄都保存起來了
            ArrayMap 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();
                    mServices.put(context, map);
                }
                map.put(c, sd);
            } else {
                sd.validate(context, handler);
            }
            return sd.getIServiceConnection();
        }
    }
    static final class ServiceDispatcher {
        private final ServiceDispatcher.InnerConnection mIServiceConnection;
        private final ServiceConnection mConnection;

        private static class ConnectionInfo {
            IBinder binder;
            IBinder.DeathRecipient deathMonitor;
        }

        private static class InnerConnection extends IServiceConnection.Stub {
            final WeakReference mDispatcher;

            InnerConnection(LoadedApk.ServiceDispatcher sd) {
                mDispatcher = new WeakReference(sd);
            }
            //這個方法就是在ActivityManagerService中執行綁定鏈接時的方法調用
            //這裡的service毫無疑問就是遠程對象執行onBind時返回的那個咯
            //所以這裡才是服務端和客戶端傳遞一個binder對象的通道,因為這個過程涉及到兩個跨進程操作,所以這麼設計是必須也是合理的
            public void connected(ComponentName name, IBinder service) throws RemoteException {
                LoadedApk.ServiceDispatcher sd = mDispatcher.get();
                if (sd != null) {
                    sd.connected(name, service);
                }
            }
        }

        private final ArrayMap mActiveConnections
            = new ArrayMap();

        ServiceConnection getServiceConnection() {
            return mConnection;
        }

        IServiceConnection getIServiceConnection() {
            return mIServiceConnection;
        }

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

        public void death(ComponentName name, IBinder service) {
            .......................
        }
        //實際執行connect
        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);
            }
        }
        
        public void doDeath(ComponentName name, IBinder service) {
            mConnection.onServiceDisconnected(name);
        }

        private final class RunConnection implements Runnable {
            RunConnection(ComponentName name, IBinder service, int command) {
                mName = name;
                mService = service;
                mCommand = command;
            }

            public void run() {
                if (mCommand == 0) {
                    doConnected(mName, mService);
                } else if (mCommand == 1) {
                    doDeath(mName, mService);
                }
            }
        }
        private final class DeathMonitor implements IBinder.DeathRecipient
        {
            DeathMonitor(ComponentName name, IBinder service) {
                mName = name;
                mService = service;
            }

            public void binderDied() {
                death(mName, mService);
            }

            final ComponentName mName;
            final IBinder mService;
        }
 }

 

後面就是bind操作了,前面講生命周期時已經有提到過的,這裡再把那個方法列一下:

 

        int bindServiceLocked(IApplicationThread caller, IBinder token,  
                Intent service, String resolvedType,  
                IServiceConnection connection, int flags, int userId) {  
            ....................  
            ServiceLookupResult res =  
                retrieveServiceLocked(service, resolvedType,  
                        Binder.getCallingPid(), Binder.getCallingUid(), userId, true, callerFg);  
            ....................          
            try {  
                if (unscheduleServiceRestartLocked(s, callerApp.info.uid, false)) {  
                    if (DEBUG_SERVICE) Slog.v(TAG, BIND SERVICE WHILE RESTART PENDING:   
                            + s);  
                }  
                ...................  
                //bindings中添加一起綁定請求,後續requestServiceBindingsLocked()流程中處理綁定接口  
                AppBindRecord b = s.retrieveAppBindingLocked(service, callerApp);  
                ....................  
                if ((flags&Context.BIND_AUTO_CREATE) != 0) {  
                    s.lastActivity = SystemClock.uptimeMillis();  
                    //如果攜帶的標志位中包含自動啟動,則進行創建服務的操作,代碼可以看前面,如果已經啟動了,其實是什麼操作也不干的  
                    if (bringUpServiceLocked(s, service.getFlags(), callerFg, false) != null) {  
                        return 0;  
                    }  
                }  
      
                if (s.app != null) {  
                    // This could have made the service more important.  
                    mAm.updateLruProcessLocked(s.app, s.app.hasClientActivities, b.client);  
                    mAm.updateOomAdjLocked(s.app);  
                }  
                  
                if (s.app != null && b.intent.received) {  
                    // Service is already running, so we can immediately  
                    // publish the connection.  
                    // 如果服務已經啟動並且有綁定過了,直接返回binder對象,這裡的conn就是前面提到的InnerConnection的代理,這裡看到了connected操作其實是由
// InnerConnection它來完成的 try { c.conn.connected(s.name, b.intent.binder); } catch (Exception e) { Slog.w(TAG, Failure sending service + s.shortName + to connection + c.conn.asBinder() + (in + c.binding.client.processName + ), e); } // If this is the first app connected back to this binding, // and the service had previously asked to be told when // rebound, then do so. // 從這裡可以看出,一般情況下,onBind只會執行一次,除非請求doRebind // 這個標志位是舊的客戶端全部unbind之後自動設置上的 if (b.intent.apps.size() == 1 && b.intent.doRebind) { requestServiceBindingLocked(s, b.intent, callerFg, true); } } else if (!b.intent.requested) { //服務還沒有綁定者,則執行後續操作將調用到onBind操作 requestServiceBindingLocked(s, b.intent, callerFg, false); } getServiceMap(s.userId).ensureNotStartingBackground(s); } finally { Binder.restoreCallingIdentity(origId); } return 1; } 

 


大家有沒有在上面注意一個問題,InnerConnection中並沒有unConnected方法,那麼解綁的時候又是如何通過這個連接通道執行回調的呢?大家可以看看前面講的unBind流程中,裡面也是沒有任何地方會執行到這個操作的,它有的只是服務端的unBind和可能執行onDestory。那麼什麼時候會執行到ServiceConnection.onServiceDisconnected,事實上只有在遠程服務端那個binder死亡才會執行到的。這個就是通過為這個binder對象注冊一個IBinder.DeathRecipient,這是binder的死亡通知機制。這裡就不講了。

 

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved