Activity bindService后销毁及unbindService 记录

729 阅读5分钟

场景一: Activity调用bindService后,不调用unbindService,直接调用finish销毁Activity,看下会对Service有什么影响?

1 ActivityThread#handleDestroyActivity

从ActivityThread#H对DESTROY_ACTIVITY消息处理开始看起。

private class H extends Handler {

    public void handleMessage(Message msg) {
        switch (msg.what) {
        
            case DESTROY_ACTIVITY:
                handleDestroyActivity((IBinder)msg.obj, msg.arg1 != 0, msg.arg2, false);
                break;

            ...
        }
    }
}

private void handleDestroyActivity(IBinder token, boolean finishing,
        int configChanges, boolean getNonConfigInstance) {
    ActivityClientRecord r = performDestroyActivity(token, finishing,
            configChanges, getNonConfigInstance);
    if (r != null) {
        
        //处理Window相关
        ...

        // getBaseContext()返回的context在启动Activity中被赋值为ContextImpl的一个实例。
        // 具体见Activity#performLaunchActivity
        Context c = r.activity.getBaseContext();

        if (c instanceof ContextImpl) {
            ((ContextImpl) c).scheduleFinalCleanup(
                    r.activity.getClass().getName(), "Activity");
        }
    }
    ...
}

ContextImpl#scheduleFinalCleanup

final void scheduleFinalCleanup(String who, String what) {
    mMainThread.scheduleContextCleanup(this, who, what);
}
final void scheduleContextCleanup(ContextImpl context, String who,
        String what) {
    ContextCleanupInfo cci = new ContextCleanupInfo();
    cci.context = context;
    cci.who = who;
    cci.what = what;
    sendMessage(H.CLEAN_UP_CONTEXT, cci);
}
case CLEAN_UP_CONTEXT:
    ContextCleanupInfo cci = (ContextCleanupInfo)msg.obj;
    cci.context.performFinalCleanup(cci.who, cci.what);
    break;
final void performFinalCleanup(String who, String what) {
    //Log.i(TAG, "Cleanup up context: " + this);
    mPackageInfo.removeContextRegistrations(getOuterContext(), who, what);
}

可以看到handleDestroyActivity主要调了ContextImpl#scheduleFinalCleanup,之后在ContextImpl、ActivityThread间相互调用,最后进入LoadedApk

2 LoadedApk#removeContextRegistrations
public void removeContextRegistrations(Context context,
        String who, String what) {
    final boolean reportRegistrationLeaks = StrictMode.vmRegistrationLeaksEnabled();
    synchronized (mReceivers) {
        // 注销未及时注销的广播
        ...
    }

    //断开已经建立的连接
    synchronized (mServices) {
        
        ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher> smap =
                mServices.remove(context);
        if (smap != null) {
            for (int i = 0; i < smap.size(); i++) {
                LoadedApk.ServiceDispatcher sd = smap.valueAt(i);
                ...
                try {
                    ActivityManagerNative.getDefault().unbindService(
                            sd.getIServiceConnection());
                } catch (RemoteException e) {
                    // system crashed, nothing we can do
                }
                sd.doForget();
            }
        }
        mUnboundServices.remove(context);
    }
}

系统对在当前Activity注册的Broadcast和Service都做相应的处理,这里只看Service的部分。AMN调用AMS,AMS再到ActiveService的unBinderServiceLocked

3 AMS#unbindService
public boolean unbindService(IServiceConnection connection) {
    synchronized (this) {
        return mServices.unbindServiceLocked(connection);
    }
}
4 ActivieServices#unbindServiceLocked
boolean unbindServiceLocked(IServiceConnection connection) {
    IBinder binder = connection.asBinder();
    ArrayList<ConnectionRecord> clist = mServiceConnections.get(binder);
    if (clist == null) {// 没有连接建立
        Slog.w(TAG, "Unbind failed: could not find connection for "
              + connection.asBinder());
        return false;
    }

    final long origId = Binder.clearCallingIdentity();
    try {
        while (clist.size() > 0) {//遍历连接集合
            ConnectionRecord r = clist.get(0);
            removeConnectionLocked(r, null, null); //依次做连接移除操作
            if (clist.size() > 0 && clist.get(0) == r) {
                // In case it didn't get removed above, do it now.
                Slog.wtf(TAG, "Connection " + r + " not removed for binder " + binder);
                clist.remove(0);
            }

            ...
        }
    } finally {
        Binder.restoreCallingIdentity(origId);
    }

    return true;
}

ActivieServices#removeConnectionLocked

void removeConnectionLocked(
    ConnectionRecord c, ProcessRecord skipApp, ActivityRecord skipAct) {
    IBinder binder = c.conn.asBinder();
    AppBindRecord b = c.binding;
    ServiceRecord s = b.service;
    
    //------------集合移除连接记录----------
    ArrayList<ConnectionRecord> clist = s.connections.get(binder); //
    if (clist != null) {
        clist.remove(c);
        if (clist.size() == 0) {
            s.connections.remove(binder);
        }
    }
    b.connections.remove(c);
    if (c.activity != null && c.activity != skipAct) {
        if (c.activity.connections != null) {
            c.activity.connections.remove(c);
        }
    }
    if (b.client != skipApp) {
        b.client.connections.remove(c);
        if ((c.flags&Context.BIND_ABOVE_CLIENT) != 0) {
            b.client.updateHasAboveClientLocked();
        }
        if (s.app != null) {
            updateServiceClientActivitiesLocked(s.app, c, true);
        }
    }
    clist = mServiceConnections.get(binder);
    if (clist != null) {
        clist.remove(c);
        if (clist.size() == 0) {
            mServiceConnections.remove(binder);
        }
    }

    mAm.stopAssociationLocked(b.client.uid, b.client.processName, s.appInfo.uid, s.name);

    if (b.connections.size() == 0) {// 当前APP所在进程已经与Service没有连接
        b.intent.apps.remove(b.client);
    }

    if (!c.serviceDead) {
        if (s.app != null && s.app.thread != null // Service正在运行中
                && b.intent.apps.size() == 0      //没有进程与当前Service连接
                && b.intent.hasBound) {           //hasBound?
            try {
                ...
                b.intent.hasBound = false;
                s.app.thread.scheduleUnbindService(s, b.intent.intent.getIntent());
            } catch (Exception e) {
                Slog.w(TAG, "Exception when unbinding service " + s.shortName, e);
                serviceProcessGoneLocked(s);
            }
        }

        if ((c.flags&Context.BIND_AUTO_CREATE) != 0) {
            boolean hasAutoCreate = s.hasAutoCreateConnections();
            ...
            //如果必要,销毁Service
            bringDownServiceIfNeededLocked(s, true, hasAutoCreate);
        }
    }
}

注意下调用scheduleUnbindService的前提条件:

 if (s.app != null && s.app.thread != null // Service正在运行中
     && b.intent.apps.size() == 0          //没有进程与当前Service存在绑定关系
     && b.intent.hasBound)                 

也就是说,如果Activity销毁时,Service还有其他活跃连接,那么不会调用Service的onUnbind、onDestroy回调

4.1 scheduleUnbindService
public final void scheduleUnbindService(IBinder token, Intent intent) {
    BindServiceData s = new BindServiceData();
    s.token = token;
    s.intent = intent;

    sendMessage(H.UNBIND_SERVICE, s);
}
private void handleUnbindService(BindServiceData data) {
    Service s = mServices.get(data.token);
    if (s != null) {
        try {
            data.intent.setExtrasClassLoader(s.getClassLoader());
            data.intent.prepareToEnterProcess();
            boolean doRebind = s.onUnbind(data.intent);// 调用Service onUnbind方法
            try {
                if (doRebind) {
                    ActivityManagerNative.getDefault().unbindFinished(
                            data.token, data.intent, doRebind);
                } else {
                    ActivityManagerNative.getDefault().serviceDoneExecuting(
                            data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0);
                }
            } catch (RemoteException ex) {
            }
        } catch (Exception e) {
            ...
        }
    }
}

handleUnbindService调用Service onUnbind回调。注意Service#onUnbind方法返回一个boolean结果doRebind,字面意思就知道该变量控制是否重新绑定Service。

4.2 bringDownServiceIfNeededLocked
private final void bringDownServiceIfNeededLocked(ServiceRecord r, boolean knowConn,
        boolean hasConn) {
    if (isServiceNeeded(r, knowConn, hasConn)) {
        return;
    }

    // Are we in the process of launching?
    if (mPendingServices.contains(r)) {
        return;
    }

    bringDownServiceLocked(r);
}

这里主要看下isServiceNeeded方法,其中ServiceRecord的startRequested字段在启动Service时被赋值为true,此时值为true。而在以下方法中ServiceRecord的startRequested字段会被赋值为false。

killServicesLocked
stopServiceLocked
stopServiceTokenLocked

也就是说当Service不再被需要时,就会执行bringDownServiceLocked的逻辑

private final boolean isServiceNeeded(ServiceRecord r, boolean knowConn, boolean hasConn) {
    // Are we still explicitly being asked to run?
    if (r.startRequested) { // true
        return true;
    }

    // Is someone still bound to us keepign us running?
    if (!knowConn) {
        hasConn = r.hasAutoCreateConnections();
    }
    if (hasConn) {
        return true;
    }

    return false;
}

看下bringDownServiceLocked的逻辑,

private final void bringDownServiceLocked(ServiceRecord r) {
    for (int conni=r.connections.size()-1; conni>=0; conni--) { // 遍历与当前Service建立的所有连接
        ArrayList<ConnectionRecord> c = r.connections.valueAt(conni);
        for (int i=0; i<c.size(); i++) {
            ConnectionRecord cr = c.get(i);
            cr.serviceDead = true; // 标识当前连接的服务已死
            try {
                cr.conn.connected(r.name, null); // 继续回调IServiceConnection connected
            } catch (Exception e) {
                ...
            }
        }
    }

    // Tell the service that it has been unbound.
    //note  (r.app != null && r.app.thread != null) 这个条件判断表明Service正在正常运行中。相当于Service被动告知要停止运行
    if (r.app != null && r.app.thread != null) {
        for (int i=r.bindings.size()-1; i>=0; i--) {
            IntentBindRecord ibr = r.bindings.valueAt(i);
     
            if (ibr.hasBound) {//如果hasBound为true就先执行scheduleUnbindService。如果已经执行过scheduleUnbindService,hasBound已被置为false
                try {
                    ...
                    ibr.hasBound = false;
                    
                    //执行unbind操作
                    r.app.thread.scheduleUnbindService(r,
                            ibr.intent.getIntent());
                } catch (Exception e) {
                    ...
                }
            }
        }
    }

    r.destroyTime = SystemClock.uptimeMillis();

    final ServiceMap smap = getServiceMap(r.userId);
    smap.mServicesByName.remove(r.name);
    smap.mServicesByIntent.remove(r.intent);
    r.totalRestartCount = 0;
    unscheduleServiceRestartLocked(r, 0, true);// 不重新启动Service

    // Also make sure it is not on the pending list.
    for (int i=mPendingServices.size()-1; i>=0; i--) {// 如果Service已经加入待启动集合,也一并移除
        if (mPendingServices.get(i) == r) {
            mPendingServices.remove(i);
        }
    }

    //重置ServiceRecord中的一些变量
    r.cancelNotification();
    r.isForeground = false;
    r.foregroundId = 0;
    r.foregroundNoti = null;

    // Clear start entries.
    r.clearDeliveredStartsLocked();
    r.pendingStarts.clear();

    if (r.app != null) {
        synchronized (r.stats.getBatteryStats()) {
            r.stats.stopLaunchedLocked();
        }
        r.app.services.remove(r);
        if (r.app.thread != null) {
            updateServiceForegroundLocked(r.app, false);
            try {
                bumpServiceExecutingLocked(r, false, "destroy");
                mDestroyingServices.add(r);
                r.destroying = true;
                mAm.updateOomAdjLocked(r.app);
                r.app.thread.scheduleStopService(r);// stop正常运行中的Service
            } catch (Exception e) {
                Slog.w(TAG, "Exception when destroying service "
                        + r.shortName, e);
                serviceProcessGoneLocked(r);
            }
        } else {
            if (DEBUG_SERVICE) Slog.v(
                TAG_SERVICE, "Removed service that has no process: " + r);
        }
    } else {
        if (DEBUG_SERVICE) Slog.v(
            TAG_SERVICE, "Removed service that is not running: " + r);
    }

    if (r.bindings.size() > 0) {
        r.bindings.clear();
    }

    
    //确保当前Service不会在后台启动
    smap.ensureNotStartingBackground(r);
}

也就是当Service不再被需要时,则所有的连接需要断开,Service调用onUnbind、onDestroy被销毁。汇总下bringDownServiceLocked的逻辑。

  1. 首先遍历当前Service已经建立的连接,依次调用IServiceConnection#connected方法,具体逻辑见4.2.1
  2. 判断当前Service正在正常运行中,(满足intentBindRecord.hasBound == true),调用Service scheduleUnbindService,具体逻辑见4.1
  3. 处理Service可能存在的重启、待启动后,执行scheduleStopService,具体逻辑见4.2.2
4.2.1

接着看IServiceConnection接口在LoadedApk#ServiceDispatcher相应的实现,

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

最终调用到ServieDispatcher#doConnected,bindService调用链也调到这里,所以这个方法是bind、unbind共用,看下unbind时的逻辑

// 注意,service传入null
public void doConnected(ComponentName name, IBinder service) {
    ServiceDispatcher.ConnectionInfo old;
    ServiceDispatcher.ConnectionInfo info;

    synchronized (this) {
        ...
        
        //bind过程已经加入该集合,所以此时old不为null
        old = mActiveConnections.get(name);
        if (old != null && old.binder == service) {//service为null, 不会进入if块
            return;
        }

        if (service != null) {//service == null
            ...

        } else {
            // The named service is being disconnected... clean up.
            mActiveConnections.remove(name); //移除<name, connectionInfo>
        }

        if (old != null) {// Service已死, 所以Client清除Service死亡通知
            old.binder.unlinkToDeath(old.deathMonitor, 0);
        }
    }

    // If there was an old service, it is not disconnected.
    if (old != null) {// 此时old != null
        mConnection.onServiceDisconnected(name); //调用ServiceConnection#onServiceDisconnected回调
    }
    // If there is a new service, it is now connected.
    if (service != null) {
        ...
    }
}
4.2.2 scheduleStopService

scheduleStopService发送STOP_SERVICE消息

case STOP_SERVICE:
    handleStopService((IBinder)msg.obj);
    maybeSnapshot();
    break;
private void handleStopService(IBinder token) {
    Service s = mServices.remove(token);
    if (s != null) {
        try {
            
            s.onDestroy(); //调用Service的onDestroy方法
            Context context = s.getBaseContext();
            if (context instanceof ContextImpl) {// 执行当前Service绑定的其他Service的清理工作
                final String who = s.getClassName();
                ((ContextImpl) context).scheduleFinalCleanup(who, "Service");
            }

            QueuedWork.waitToFinish();

            try {
                ActivityManagerNative.getDefault().serviceDoneExecuting(
                        token, SERVICE_DONE_EXECUTING_STOP, 0, 0);
            } catch (RemoteException e) {
                // nothing to do.
                
            }
        } catch (Exception e) {
             ...
        }
    } else {
        Slog.i(TAG, "handleStopService: token=" + token + " not found.");
    }
    //Slog.i(TAG, "Running services: " + mServices);
}

该方法首先执行Service的onDestroy方法。然后继续调用ContextImpl#scheduleFinalCleanup执行当前Service绑定的其他Service的清理工作。这里可能有疑惑,为啥又调一次scheduleFinalCleanup? 文章开头调用是Activity的销毁引发的已绑定Service的清理工作。这里要做一个区分。

场景二、 bindService之后调用unbindService

unbindService的调用链和场景一的大部分场景比较重合,简单列下代码


public void unbindService(ServiceConnection conn) {
    if (conn == null) {
        throw new IllegalArgumentException("connection is null");
    }
    if (mPackageInfo != null) {
        IServiceConnection sd = mPackageInfo.forgetServiceDispatcher(
                getOuterContext(), conn);
        try {
            ActivityManagerNative.getDefault().unbindService(sd);
        } catch (RemoteException e) {
        }
    } else {
        throw new RuntimeException("Not supported in system context");
    }
}
public boolean unbindService(IServiceConnection connection) {
    synchronized (this) {
        return mServices.unbindServiceLocked(connection);
    }
}

mServices.unbindServiceLocked及往下参照上面第4点即可