bindservice流程梳理

来源:互联网 发布:手立视高清网络摄像机 编辑:程序博客网 时间:2024/06/06 03:36

看了一天了终于把bindservice大致梳理了一遍

和service启动过程一样,service绑定也是从contextWrapper开始,具体怎么开始可以看我另一篇博客--context

程序最终调用contextImpl中的bindServiceCommon方法

    private boolean bindServiceCommon(Intent service, ServiceConnection conn, int flags,            UserHandle user) {        IServiceConnection sd;        if (conn == null) {            throw new IllegalArgumentException("connection is null");        }        if (mPackageInfo != null) {            sd = mPackageInfo.getServiceDispatcher(conn, getOuterContext(),                    mMainThread.getHandler(), 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();            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;        } catch (RemoteException e) {            return false;        }    }
首先将serviceConnection对象转化为一个实现了IServiceConnection对象,从getServiceDispatcher可以看出,实现了IServiceConnection接口的对象其实是LoaderApk的一个内部类

    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();        }    }
我们进入内部类一探究竟

    static final class ServiceDispatcher {        private final ServiceDispatcher.InnerConnection mIServiceConnection;        private final ServiceConnection mConnection;        private final Context mContext;        private final Handler mActivityThread;        private final ServiceConnectionLeaked mLocation;        private final int mFlags;        private RuntimeException mUnbindLocation;        private boolean mDied;        private boolean mForgotten;        private static class ConnectionInfo {            IBinder binder;            IBinder.DeathRecipient deathMonitor;        }        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);                }            }        }        private final ArrayMap<ComponentName, ServiceDispatcher.ConnectionInfo> mActiveConnections            = new ArrayMap<ComponentName, ServiceDispatcher.ConnectionInfo>();        ServiceDispatcher(ServiceConnection conn,                Context context, Handler activityThread, int flags) {            mIServiceConnection = new InnerConnection(this);            mConnection = conn;            mContext = context;            mActivityThread = activityThread;            mLocation = new ServiceConnectionLeaked(null);            mLocation.fillInStackTrace();            mFlags = flags;        }        void validate(Context context, Handler activityThread) {            if (mContext != context) {                throw new RuntimeException(                    "ServiceConnection " + mConnection +                    " registered with differing Context (was " +                    mContext + " now " + context + ")");            }            if (mActivityThread != activityThread) {                throw new RuntimeException(                    "ServiceConnection " + mConnection +                    " registered with differing handler (was " +                    mActivityThread + " now " + activityThread + ")");            }        }        void doForget() {            synchronized(this) {                for (int i=0; i<mActiveConnections.size(); i++) {                    ServiceDispatcher.ConnectionInfo ci = mActiveConnections.valueAt(i);                    ci.binder.unlinkToDeath(ci.deathMonitor, 0);                }                mActiveConnections.clear();                mForgotten = true;            }        }        ServiceConnectionLeaked getLocation() {            return mLocation;        }        ServiceConnection getServiceConnection() {            return mConnection;        }        IServiceConnection getIServiceConnection() {            return mIServiceConnection;        }        int getFlags() {            return mFlags;        }        void setUnbindLocation(RuntimeException ex) {            mUnbindLocation = ex;        }        RuntimeException getUnbindLocation() {            return mUnbindLocation;        }        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) {            ServiceDispatcher.ConnectionInfo old;            synchronized (this) {                mDied = true;                old = mActiveConnections.remove(name);                if (old == null || old.binder != service) {                    // Death for someone different than who we last                    // reported...  just ignore it.                    return;                }                old.binder.unlinkToDeath(old.deathMonitor, 0);            }            if (mActivityThread != null) {                mActivityThread.post(new RunConnection(name, service, 1));            } else {                doDeath(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);            }        }        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);                }            }            final ComponentName mName;            final IBinder mService;            final int mCommand;        }        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;        }    }
发现原来实现了IServiceConnection接口的对象是InnerConnection类,这个类继承于IServiceConnection.stud。

之所以要转换成InnerConnection对象,是因为服务的绑定有可能是跨进程的,serviceconnection对象必须借助BInder才能让service端回调自己的方法,而InnerConnection充当了binder的角色,因为作者没找到IServiceConnection的源码,所以作者猜测IServiceConnection.stud应该继承binder类。

忘记分析getservicedispatcher源码了

    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();        }    }
在上面的代码中,mservice是一个Arraymap

private final ArrayMap<Context, ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher>> mServices
就是说,我们可以通过context取出一个ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher>,得到这个map以后,我们可以通过serviceConnection取出一个ServiceDispatcher,而ServiceDispatcher里保存了ServiceConnection(构造时传入),InnerConnection。当service与客户端建立连接后,系统就会通过InnerConnection来调用serviceConnect中的onService方法。

然后我们回到contextImpl中来,最后调用ActivityManagernative.getdefalut进入AMS

调用和Activity启动差不多

    public int bindService(IApplicationThread caller, IBinder token,            Intent service, String resolvedType,            IServiceConnection connection, int flags, int userId) {        enforceNotIsolatedCaller("bindService");        // Refuse possible leaked file descriptors        if (service != null && service.hasFileDescriptors() == true) {            throw new IllegalArgumentException("File descriptors passed in Intent");        }        synchronized(this) {            return mServices.bindServiceLocked(caller, token, service, resolvedType,                    connection, flags, userId);        }    }
    int bindServiceLocked(IApplicationThread caller, IBinder token,            Intent service, String resolvedType,            IServiceConnection connection, int flags, int userId) {        if (DEBUG_SERVICE) Slog.v(TAG, "bindService: " + service                + " type=" + resolvedType + " conn=" + connection.asBinder()                + " flags=0x" + Integer.toHexString(flags));        final ProcessRecord callerApp = mAm.getRecordForAppLocked(caller);        if (callerApp == null) {            throw new SecurityException(                    "Unable to find app for caller " + caller                    + " (pid=" + Binder.getCallingPid()                    + ") when binding service " + service);        }        ActivityRecord activity = null;        if (token != null) {            activity = ActivityRecord.isInStackLocked(token);            if (activity == null) {                Slog.w(TAG, "Binding with unknown activity: " + token);                return 0;            }        }        int clientLabel = 0;        PendingIntent clientIntent = null;        if (callerApp.info.uid == Process.SYSTEM_UID) {            // Hacky kind of thing -- allow system stuff to tell us            // what they are, so we can report this elsewhere for            // others to know why certain services are running.            try {                clientIntent = service.getParcelableExtra(Intent.EXTRA_CLIENT_INTENT);            } catch (RuntimeException e) {            }            if (clientIntent != null) {                clientLabel = service.getIntExtra(Intent.EXTRA_CLIENT_LABEL, 0);                if (clientLabel != 0) {                    // There are no useful extras in the intent, trash them.                    // System code calling with this stuff just needs to know                    // this will happen.                    service = service.cloneFilter();                }            }        }        if ((flags&Context.BIND_TREAT_LIKE_ACTIVITY) != 0) {            mAm.enforceCallingPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS,                    "BIND_TREAT_LIKE_ACTIVITY");        }        final boolean callerFg = callerApp.setSchedGroup != Process.THREAD_GROUP_BG_NONINTERACTIVE;        ServiceLookupResult res =            retrieveServiceLocked(service, resolvedType,                    Binder.getCallingPid(), Binder.getCallingUid(), userId, true, callerFg);        if (res == null) {            return 0;        }        if (res.record == null) {            return -1;        }        ServiceRecord s = res.record;        final long origId = Binder.clearCallingIdentity();        try {            if (unscheduleServiceRestartLocked(s, callerApp.info.uid, false)) {                if (DEBUG_SERVICE) Slog.v(TAG, "BIND SERVICE WHILE RESTART PENDING: "                        + s);            }            if ((flags&Context.BIND_AUTO_CREATE) != 0) {                s.lastActivity = SystemClock.uptimeMillis();                if (!s.hasAutoCreateConnections()) {                    // This is the first binding, let the tracker know.                    ProcessStats.ServiceState stracker = s.getTracker();                    if (stracker != null) {                        stracker.setBound(true, mAm.mProcessStats.getMemFactorLocked(),                                s.lastActivity);                    }                }            }            mAm.startAssociationLocked(callerApp.uid, callerApp.processName,                    s.appInfo.uid, s.name, s.processName);            AppBindRecord b = s.retrieveAppBindingLocked(service, callerApp);            ConnectionRecord c = new ConnectionRecord(b, activity,                    connection, flags, clientLabel, clientIntent);            IBinder binder = connection.asBinder();            ArrayList<ConnectionRecord> clist = s.connections.get(binder);            if (clist == null) {                clist = new ArrayList<ConnectionRecord>();                s.connections.put(binder, clist);            }            clist.add(c);            b.connections.add(c);            if (activity != null) {                if (activity.connections == null) {                    activity.connections = new HashSet<ConnectionRecord>();                }                activity.connections.add(c);            }            b.client.connections.add(c);            if ((c.flags&Context.BIND_ABOVE_CLIENT) != 0) {                b.client.hasAboveClient = true;            }            if (s.app != null) {                updateServiceClientActivitiesLocked(s.app, c, true);            }            clist = mServiceConnections.get(binder);            if (clist == null) {                clist = new ArrayList<ConnectionRecord>();                mServiceConnections.put(binder, clist);            }            clist.add(c);            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) {                if ((flags&Context.BIND_TREAT_LIKE_ACTIVITY) != 0) {                    s.app.treatLikeActivity = true;                }                // This could have made the service more important.                mAm.updateLruProcessLocked(s.app, s.app.hasClientActivities                        || s.app.treatLikeActivity, b.client);                mAm.updateOomAdjLocked(s.app);            }            if (DEBUG_SERVICE) Slog.v(TAG, "Bind " + s + " with " + b                    + ": received=" + b.intent.received                    + " apps=" + b.intent.apps.size()                    + " doRebind=" + b.intent.doRebind);            if (s.app != null && b.intent.received) {                // Service is already running, so we can immediately                // publish the connection.                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.                if (b.intent.apps.size() == 1 && b.intent.doRebind) {                    requestServiceBindingLocked(s, b.intent, callerFg, true);                }            } else if (!b.intent.requested) {                requestServiceBindingLocked(s, b.intent, callerFg, false);            }            getServiceMap(s.userId).ensureNotStartingBackground(s);        } finally {            Binder.restoreCallingIdentity(origId);        }        return 1;    }
    private final String bringUpServiceLocked(ServiceRecord r,            int intentFlags, boolean execInFg, boolean whileRestarting) {        //Slog.i(TAG, "Bring up service:");        //r.dump("  ");        if (r.app != null && r.app.thread != null) {            sendServiceArgsLocked(r, execInFg, false);            return null;        }        if (!whileRestarting && r.restartDelay > 0) {            // If waiting for a restart, then do nothing.            return null;        }        if (DEBUG_SERVICE) Slog.v(TAG, "Bringing up " + r + " " + r.intent);        // We are now bringing the service up, so no longer in the        // restarting state.        if (mRestartingServices.remove(r)) {            r.resetRestartCounter();            clearRestartingIfNeededLocked(r);        }        // Make sure this service is no longer considered delayed, we are starting it now.        if (r.delayed) {            if (DEBUG_DELAYED_STARTS) Slog.v(TAG, "REM FR DELAY LIST (bring up): " + r);            getServiceMap(r.userId).mDelayedStartList.remove(r);            r.delayed = false;        }        // Make sure that the user who owns this service is started.  If not,        // we don't want to allow it to run.        if (mAm.mStartedUsers.get(r.userId) == null) {            String msg = "Unable to launch app "                    + r.appInfo.packageName + "/"                    + r.appInfo.uid + " for service "                    + r.intent.getIntent() + ": user " + r.userId + " is stopped";            Slog.w(TAG, msg);            bringDownServiceLocked(r);            return msg;        }        // Service is now being launched, its package can't be stopped.        try {            AppGlobals.getPackageManager().setPackageStoppedState(                    r.packageName, false, r.userId);        } catch (RemoteException e) {        } catch (IllegalArgumentException e) {            Slog.w(TAG, "Failed trying to unstop package "                    + r.packageName + ": " + e);        }        final boolean isolated = (r.serviceInfo.flags&ServiceInfo.FLAG_ISOLATED_PROCESS) != 0;        final String procName = r.processName;        ProcessRecord app;        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 (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.            }        } else {            // If this service runs in an isolated process, then each time            // we call startProcessLocked() we will get a new isolated            // process, starting another process if we are currently waiting            // for a previous process to come up.  To deal with this, we store            // in the service any current isolated process it is running in or            // waiting to have come up.            app = r.isolatedProc;        }        // Not running -- get it started, and enqueue this service record        // to be executed when the app comes up.        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;            }        }        if (!mPendingServices.contains(r)) {            mPendingServices.add(r);        }        if (r.delayedStop) {            // Oh and hey we've already been asked to stop!            r.delayedStop = false;            if (r.startRequested) {                if (DEBUG_DELAYED_STARTS) Slog.v(TAG, "Applying delayed stop (in bring up): " + r);                stopServiceLocked(r);            }        }        return null;    }
    private final void realStartServiceLocked(ServiceRecord r,            ProcessRecord app, boolean execInFg) throws RemoteException {        if (app.thread == null) {            throw new RemoteException();        }        if (DEBUG_MU)            Slog.v(TAG_MU, "realStartServiceLocked, ServiceRecord.uid = " + r.appInfo.uid                    + ", ProcessRecord.uid = " + app.uid);        r.app = app;        r.restartTime = r.lastActivity = SystemClock.uptimeMillis();        app.services.add(r);        bumpServiceExecutingLocked(r, execInFg, "create");        mAm.updateLruProcessLocked(app, false, null);        mAm.updateOomAdjLocked();        boolean created = false;        try {            if (LOG_SERVICE_START_STOP) {                String nameTerm;                int lastPeriod = r.shortName.lastIndexOf('.');                nameTerm = lastPeriod >= 0 ? r.shortName.substring(lastPeriod) : r.shortName;                EventLogTags.writeAmCreateService(                        r.userId, System.identityHashCode(r), nameTerm, r.app.uid, r.app.pid);            }            synchronized (r.stats.getBatteryStats()) {                r.stats.startLaunchedLocked();            }            mAm.ensurePackageDexOpt(r.serviceInfo.packageName);            app.forceProcessStateUpTo(ActivityManager.PROCESS_STATE_SERVICE);            app.thread.scheduleCreateService(r, r.serviceInfo,                    mAm.compatibilityInfoForPackageLocked(r.serviceInfo.applicationInfo),                    app.repProcState);            r.postNotification();            created = true;        } catch (DeadObjectException e) {            Slog.w(TAG, "Application dead when creating service " + r);            mAm.appDiedLocked(app);        } finally {            if (!created) {                app.services.remove(r);                r.app = null;                scheduleServiceRestartLocked(r, false);                return;            }        }        requestServiceBindingsLocked(r, execInFg);        updateServiceClientActivitiesLocked(app, null, true);        // If the service is in the started state, and there are no        // pending arguments, then fake up one so its onStartCommand() will        // be called.        if (r.startRequested && r.callStart && r.pendingStarts.size() == 0) {            r.pendingStarts.add(new ServiceRecord.StartItem(r, false, r.makeNextStartId(),                    null, null));        }        sendServiceArgsLocked(r, execInFg, true);        if (r.delayed) {            if (DEBUG_DELAYED_STARTS) Slog.v(TAG, "REM FR DELAY LIST (new proc): " + r);            getServiceMap(r.userId).mDelayedStartList.remove(r);            r.delayed = false;        }        if (r.delayedStop) {            // Oh and hey we've already been asked to stop!            r.delayedStop = false;            if (r.startRequested) {                if (DEBUG_DELAYED_STARTS) Slog.v(TAG, "Applying delayed stop (from start): " + r);                stopServiceLocked(r);            }        }    }

不同的是,service的绑定过程会在requestServiceBindingsLocked(r, execInFg);中实现

    private final boolean requestServiceBindingLocked(ServiceRecord r,            IntentBindRecord i, boolean execInFg, boolean rebind) {        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);                r.app.thread.scheduleBindService(r, i.intent.getIntent(), rebind,                        r.app.repProcState);                if (!rebind) {                    i.requested = true;                }                i.hasBound = true;                i.doRebind = false;            } catch (RemoteException e) {                if (DEBUG_SERVICE) Slog.v(TAG, "Crashed while binding " + r);                return false;            }        }        return true;    }
然后调用 r.app.thread.scheduleBindService(r, i.intent.getIntent(), rebind,r.app.repProcState);回调Activity中的方法

        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);        }
把所有数据打包装到bindserviceData中,方便以后取出


handlemessage


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

取出服务,并调用onbind方法,到这里,service基本就绑定完成了








0 0
原创粉丝点击