likes
comments
collection
share

【源码解析】bindService的生命周期分析

作者站长头像
站长
· 阅读数 5

一、引言

我们都知道,启动一个Service有两种方式: 1、通过startService启动一个Service。 这种方式启动的Service有自己独立的生命周期。onCreate->onStart->onDestroy。 2、通过bindService启动一个Service。 这种方式启动的Service的生命周期和启动它的Activity绑定在了一起。

今天我们就通过分析源码的方式,来解释一下为什么bindService时,Service的生命周期和Activity是绑定的。

二、源码分析

Service的生命周期和Activity是绑定的这个结论出发,我们可以得到下面这个论断:

当Activity被销毁时,其绑定的Service也会被销毁。即当Activity调用了onDestroy方法,其绑定的Service也会调用onDestroy方法。

2.1、分析阶段1

Android系统是通过消息驱动机制进行工作的,在Activity被销毁时,ActivityThread的scheduleDestroyActivity方法会被执行,如下所示:

public final void scheduleDestroyActivity(IBinder token, boolean finishing,
        int configChanges) {
    sendMessage(H.DESTROY_ACTIVITY, token, finishing ? 1 : 0,
            configChanges);
}

逻辑很清晰,直接调用了sendMessage方法,发送了一个类型为H.DESTROY_ACTIVITY的消息。最终ActivityThread的内部类H对该消息进行了处理,其处理逻辑如下所示:

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

handleMessage方法中调用了handleDestroyActivity方法,如下所示:

private void handleDestroyActivity(IBinder token, boolean finishing,
        int configChanges, boolean getNonConfigInstance) {
    ...省略
    if (finishing) {
        try {
            ActivityManager.getService().activityDestroyed(token);
        } catch (RemoteException ex) {
            throw ex.rethrowFromSystemServer();
        }
    }
    mSomeActivitiesChanged = true;
}

handleDestroyActivity方法最终调用了ActivityManagerService的activityDestroyed方法。

2.2、分析阶段2

承接上面的逻辑,我们跳转到ActivityManagerService,并找到activityDestroyed方法,如下所示:

public final void activityDestroyed(IBinder token) {
    synchronized (this) {
        ActivityStack stack = ActivityRecord.getStackLocked(token);
        if (stack != null) {
            stack.activityDestroyedLocked(token, "activityDestroyed");
        }
    }
}

在activityDestroyed方法中,通过ActivityRecord.getStackLocked方法获取一个ActivityStack对象,并调用ActivityStack的activityDestroyedLocked方法,如下所示:

final void activityDestroyedLocked(IBinder token, String reason) {
    final long origId = Binder.clearCallingIdentity();
    try {
        ActivityRecord r = ActivityRecord.forTokenLocked(token);
        if (r != null) {
            mHandler.removeMessages(DESTROY_TIMEOUT_MSG, r);
        }

        if (isInStackLocked(r) != null) {
            if (r.state == ActivityState.DESTROYING) {
                cleanUpActivityLocked(r, true, false);
                removeActivityFromHistoryLocked(r, reason);
            }
        }
        mStackSupervisor.resumeFocusedStackTopActivityLocked();
    } finally {
        Binder.restoreCallingIdentity(origId);
    }
}

当判断ActivityRecord对象的state为ActivityState.DESTROYING时,又调用了cleanUpActivityLocked方法,注意这里的第二个参数值为true。如下所示:

private void cleanUpActivityLocked(ActivityRecord r, boolean cleanServices, boolean setState) {
    onActivityRemovedFromStack(r);

    r.deferRelaunchUntilPaused = false;
    r.frozenBeforeDestroy = false;
    
    ...省略

    if (cleanServices) {
        cleanUpActivityServicesLocked(r);
    }

    removeTimeoutsForActivityLocked(r);
    mWindowManager.notifyAppRelaunchesCleared(r.appToken);
}

从上一步骤可以看到,cleanServices的参数值为true,所以这里调用了cleanUpActivityServicesLocked方法,如下所示:

private void cleanUpActivityServicesLocked(ActivityRecord r) {
    if (r.connections != null) {
        Iterator<ConnectionRecord> it = r.connections.iterator();
        while (it.hasNext()) {
            ConnectionRecord c = it.next();
            mService.mServices.removeConnectionLocked(c, null, r);
        }
        r.connections = null;
    }
}

2.3、分析阶段3

承接上面的逻辑,在cleanUpActivityServicesLocked方法中,执行了一个判空操作r.connection != null,而从Service的工作过程这篇文章可知,当Service绑定在Activity时,在ActiveService类的bindServiceLocked方法中会将为ActivityRecord对象的connections赋值。因此得出以下结论:

当Activity没有绑定任何Service时,然后cleanUpActivityServicesLocked方法内的逻辑并不会执行

所以,当Activity绑定了Service时,会继续执行ActiveServices的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) {
            //1、将ConnectionRecord对象从ActivityRecord对象的connections中去掉
            c.activity.connections.remove(c);
        }
    }
    
    ...省略
    if (!c.serviceDead) {
        if (s.app != null && s.app.thread != null && b.intent.apps.size() == 0
                && b.intent.hasBound) {
            try {
                bumpServiceExecutingLocked(s, false, "unbind");
                if (b.client != s.app && (c.flags&Context.BIND_WAIVE_PRIORITY) == 0
                        && s.app.setProcState <= ActivityManager.PROCESS_STATE_RECEIVER) {
                    mAm.updateLruProcessLocked(s.app, false, null);
                }
                mAm.updateOomAdjLocked(s.app, true);
                b.intent.hasBound = false;
                b.intent.doRebind = 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);
            }
        }
        mPendingServices.remove(s);

        if ((c.flags&Context.BIND_AUTO_CREATE) != 0) {
            boolean hasAutoCreate = s.hasAutoCreateConnections();
            if (!hasAutoCreate) {
                if (s.tracker != null) {
                    s.tracker.setBound(false, mAm.mProcessStats.getMemFactorLocked(),
                            SystemClock.uptimeMillis());
                }
            }
            //2、调用bringDownServiceIfNeededLocked方法
            bringDownServiceIfNeededLocked(s, true, hasAutoCreate);
        }
    }
}

上面的代码有点长,但是总体来说就做了两步逻辑: 1、将ConnectionRecord对象从ActivityRecord对象的connections中去掉。 2、调用bringDownServiceIfNeededLocked方法,而bringDownServiceIfNeededLocked方法又调用了bringDownServiceLocked方法,如下所示:

private final void bringDownServiceLocked(ServiceRecord r) {
    

    // Tell the service that it has been unbound.
    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) {
                try {
                    bumpServiceExecutingLocked(r, false, "bring down unbind");
                    mAm.updateOomAdjLocked(r.app, true);
                    ibr.hasBound = false;
                    ibr.requested = false;
                    //1、调用ActivityThread的scheduleUnbindService方法
                    r.app.thread.scheduleUnbindService(r,
                            ibr.intent.getIntent());
                } catch (Exception e) {
                    Slog.w(TAG, "Exception when unbinding service "
                            + r.shortName, e);
                    serviceProcessGoneLocked(r);
                }
            }
        }
    }
    ...省略

    if (r.app != null) {
        synchronized (r.stats.getBatteryStats()) {
            r.stats.stopLaunchedLocked();
        }
        r.app.services.remove(r);
        if (r.whitelistManager) {
            updateWhitelistManagerLocked(r.app);
        }
        if (r.app.thread != null) {
            updateServiceForegroundLocked(r.app, false);
            try {
                bumpServiceExecutingLocked(r, false, "destroy");
                mDestroyingServices.add(r);
                r.destroying = true;
                mAm.updateOomAdjLocked(r.app, true);
                //2、调用了ActivityThread的scheduleStopService方法
                r.app.thread.scheduleStopService(r);
            } catch (Exception e) {
                
            }
        }
    }

    ...省略
}

上面的代码逻辑主要做了两步: 1、调用了ActivityThread的scheduleUnbindService方法。该方法主要是将绑定的Service进行解绑,最终会调用Service的onUnbind方法。 2、调用了ActivityThread的scheduleStopService方法。该方法会将绑定的Service进行销毁,最终会调用Service的onDestroy方法。

至此,我们从源码分析中论证了上面的结论:通过bindService启动Service时,Service的生命周期和Activity的生命周期是一致的。当Activity被销毁时,Service也会被销毁。