Service启动与绑定原理 - 后台任务的正确打开方式

摘要

本文深入剖析Android Service组件的启动(startService)和绑定(bindService)两种使用方式的底层实现原理。基于AOSP源码追踪从应用层调用到ServiceManagerService处理、Service实例创建、生命周期回调的完整链路。文章详细分析前台服务、IntentService、AIDL跨进程通信等核心技术,并结合某IoT项目实战经验,提供Service使用的最佳实践和性能优化建议。

关键词:Service启动流程、bindService原理、ServiceManagerService、AIDL、前台服务、ANR分析


一、引言

1.1 Service的重要性

Service是Android四大组件之一,专门用于处理后台任务。无论是音乐播放、文件下载、数据同步还是IoT设备的长连接管理,Service都扮演着核心角色。

应用场景

  • 后台数据处理(日志上传、数据同步)
  • 长连接维持(IoT设备通信、推送服务)
  • 音视频播放(MediaPlayer后台播放)
  • 定时任务(闹钟、提醒)

1.2 Service的两种使用方式

方式 生命周期 通信方式 典型场景
startService 独立于调用者 单向通信 后台下载、日志上传
bindService 依赖调用者 双向通信 跨进程调用、实时数据交互

1.3 核心类概览

ContextImpl

ActivityManagerService

ActiveServices

ServiceRecord

ProcessRecord

ApplicationThread

ActivityThread

Service实例


二、startService启动流程

2.1 应用层调用入口

// 应用代码
Intent intent = new Intent(this, MyService.class);
intent.putExtra("key", "value");
startService(intent);

2.2 ContextImpl.startService()

// frameworks/base/core/java/android/app/ContextImpl.java
@Override
public ComponentName startService(Intent service) {
    warnIfCallingFromSystemProcess();
    return startServiceCommon(service, false, mUser);
}

private ComponentName startServiceCommon(Intent service, boolean requireForeground,
        UserHandle user) {
    try {
        // 验证Intent
        validateServiceIntent(service);
        service.prepareToLeaveProcess(this);
        // 调用AMS
        ComponentName cn = ActivityManager.getService().startService(
            mMainThread.getApplicationThread(), service,
            service.resolveTypeIfNeeded(getContentResolver()), requireForeground,
            getOpPackageName(), user.getIdentifier());
        if (cn != null) {
            if (cn.getPackageName().equals("!")) {
                throw new SecurityException(
                        "Not allowed to start service " + service
                        + " without permission " + cn.getClassName());
            } else if (cn.getPackageName().equals("!!")) {
                throw new SecurityException(
                        "Unable to start service " + service
                        + ": " + cn.getClassName());
            } else if (cn.getPackageName().equals("?")) {
                throw new IllegalStateException(
                        "Not allowed to start service " + service + ": " + cn.getClassName());
            }
        }
        return cn;
    } catch (RemoteException e) {
        throw e.rethrowFromSystemServer();
    }
}

2.3 ActivityManagerService处理

// frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
@Override
public ComponentName startService(IApplicationThread caller, Intent service,
        String resolvedType, boolean requireForeground, String callingPackage, int userId)
        throws TransactionTooLargeException {
    enforceNotIsolatedCaller("startService");

    // 拒绝可能包含文件描述符的Intent
    if (service != null && service.hasFileDescriptors() == true) {
        throw new IllegalArgumentException("File descriptors passed in Intent");
    }

    if (callingPackage == null) {
        throw new IllegalArgumentException("callingPackage cannot be null");
    }

    synchronized(this) {
        final int callingPid = Binder.getCallingPid();
        final int callingUid = Binder.getCallingUid();
        final long origId = Binder.clearCallingIdentity();
        ComponentName res;
        try {
            // 委托给ActiveServices处理
            res = mServices.startServiceLocked(caller, service,
                    resolvedType, callingPid, callingUid,
                    requireForeground, callingPackage, userId);
        } finally {
            Binder.restoreCallingIdentity(origId);
        }
        return res;
    }
}

2.4 ActiveServices.startServiceLocked()

// frameworks/base/services/core/java/com/android/server/am/ActiveServices.java
ComponentName startServiceLocked(IApplicationThread caller, Intent service,
        String resolvedType, int callingPid, int callingUid, boolean fgRequired,
        String callingPackage, final int userId)
        throws TransactionTooLargeException {

    final boolean callerFg;
    if (caller != null) {
        final ProcessRecord callerApp = mAm.getRecordForAppLocked(caller);
        if (callerApp == null) {
            throw new SecurityException("Unable to find app for caller " + caller);
        }
        callerFg = callerApp.setSchedGroup != ProcessList.SCHED_GROUP_BACKGROUND;
    } else {
        callerFg = true;
    }

    // 解析Service组件
    ServiceLookupResult res =
        retrieveServiceLocked(service, resolvedType, callingPackage,
                callingPid, callingUid, userId, true, callerFg, false, false);
    if (res == null) {
        return null;
    }
    if (res.record == null) {
        return new ComponentName("!", res.permission != null
                ? res.permission : "private to package");
    }

    ServiceRecord r = res.record;

    // 权限检查
    if (!requestStartTargetPermissionsReviewIfNeededLocked(r, callingPackage,
            callingUid, service, callerFg, userId)) {
        return null;
    }

    // 前台服务检查
    if (fgRequired) {
        if (!r.isForeground) {
            // 需要启动为前台服务但未设置
            return new ComponentName("?", "foreground service required");
        }
    }

    // 后台启动限制检查 (Android 8.0+)
    if (!r.mAppInfo.isSystemApp()) {
        boolean allowed = false;
        if (callerApp != null && callerApp.setSchedGroup != ProcessList.SCHED_GROUP_BACKGROUND) {
            // 前台应用可以启动后台服务
            allowed = true;
        } else if (mAm.isUidActiveLocked(callingUid)) {
            // UID处于活跃状态
            allowed = true;
        }
        if (!allowed && !fgRequired) {
            // Android 8.0+ 后台启动限制
            return new ComponentName("?", "background service restriction");
        }
    }

    // 真正的启动逻辑
    return startServiceInnerLocked(r, service, callingUid, callingPid,
            fgRequired, callerFg, null);
}

2.5 启动Service实例

// frameworks/base/services/core/java/com/android/server/am/ActiveServices.java
ComponentName startServiceInnerLocked(ServiceRecord r, Intent service,
        int callingUid, int callingPid, boolean fgRequired, boolean callerFg,
        Bundle options) throws TransactionTooLargeException {

    // Service状态更新
    r.callStart = false;
    r.lastActivity = SystemClock.uptimeMillis();
    r.startRequested = true;
    r.delayedStop = false;
    r.fgRequired = fgRequired;
    r.pendingStarts.add(new ServiceRecord.StartItem(r, false, r.makeNextStartId(),
            service, neededGrants, callingUid));

    // 前台服务特殊处理
    if (fgRequired) {
        r.fgWaiting = true;
        scheduleServiceForegroundTransitionTimeoutLocked(r);
    }

    final ServiceMap smap = getServiceMapLocked(r.userId);
    boolean addToStarting = false;

    // 非前台服务的特殊处理
    if (!callerFg && !fgRequired && r.app == null
            && mAm.mUserController.hasStartedUserState(r.userId)) {
        ProcessRecord proc = mAm.getProcessRecordLocked(r.processName, r.appInfo.uid, false);
        if (proc == null || proc.curProcState > ActivityManager.PROCESS_STATE_RECEIVER) {
            // 延迟启动服务,避免同时启动多个后台服务
            if (smap.mStartingBackground.size() >= mMaxStartingBackground) {
                smap.mDelayedStartList.add(r);
                r.delayed = true;
                return r.name;
            }
            addToStarting = true;
        }
    }

    // 启动Service
    return startServiceInnerLocked(smap, service, r, callerFg, addToStarting);
}

ComponentName startServiceInnerLocked(ServiceMap smap, Intent service,
        ServiceRecord r, boolean callerFg, boolean addToStarting)
        throws TransactionTooLargeException {

    r.callStart = false;
    synchronized (r.stats.getBatteryStats()) {
        r.stats.startRunningLocked();
    }

    // 启动Service(创建进程或在已有进程中启动)
    String error = bringUpServiceLocked(r, service.getFlags(), callerFg, false, false);
    if (error != null) {
        return new ComponentName("!!", error);
    }

    if (r.startRequested && addToStarting) {
        boolean first = smap.mStartingBackground.size() == 0;
        smap.mStartingBackground.add(r);
        r.startingBgTimeout = SystemClock.uptimeMillis() + mAm.mConstants.BG_START_TIMEOUT;
        if (first) {
            smap.rescheduleDelayedStartsLocked();
        }
    } else if (callerFg || r.fgRequired) {
        smap.ensureNotStartingBackgroundLocked(r);
    }

    return r.name;
}

2.6 bringUpServiceLocked()

// frameworks/base/services/core/java/com/android/server/am/ActiveServices.java
private String bringUpServiceLocked(ServiceRecord r, int intentFlags,
        boolean execInFg, boolean whileRestarting, boolean permissionsReviewRequired)
        throws TransactionTooLargeException {

    if (r.app != null && r.app.thread != null) {
        // Service已在运行,直接调用onStartCommand
        sendServiceArgsLocked(r, execInFg, false);
        return null;
    }

    if (!whileRestarting && mRestartingServices.contains(r)) {
        // 等待重启完成
        return null;
    }

    // 从延迟启动列表移除
    if (mDelayedStartList.remove(r)) {
        // ...
    }

    // 确保拥有者已启动
    if (!mAm.mUserController.hasStartedUserState(r.userId)) {
        String msg = "Unable to launch service " + r.intent.getIntent()
                + " U=" + r.userId + ": user " + r.userId + " is stopped";
        return msg;
    }

    // 进程启动
    final boolean isolated = (r.serviceInfo.flags & ServiceInfo.FLAG_ISOLATED_PROCESS) != 0;
    final String procName = r.processName;
    HostingRecord hostingRecord = new HostingRecord("service", r.instanceName);
    ProcessRecord app;

    if (!isolated) {
        app = mAm.getProcessRecordLocked(procName, r.appInfo.uid, false);
        if (app != null && app.thread != null) {
            try {
                // 在已有进程中创建Service
                realStartServiceLocked(r, app, execInFg);
                return null;
            } catch (TransactionTooLargeException e) {
                throw e;
            } catch (RemoteException e) {
                // 进程死亡
            }
        }
    } else {
        app = r.isolatedProc;
    }

    // 进程不存在,需要启动新进程
    if (app == null && !permissionsReviewRequired) {
        if ((app=mAm.startProcessLocked(procName, r.appInfo, true, intentFlags,
                hostingRecord, false, isolated, false)) == null) {
            String msg = "Unable to launch service " + r.intent.getIntent()
                    + " from package " + r.packageName
                    + ": process " + procName + " could not be started";
            return msg;
        }
        if (isolated) {
            r.isolatedProc = app;
        }
    }

    // 加入待启动列表
    if (!mPendingServices.contains(r)) {
        mPendingServices.add(r);
    }

    if (r.delayedStop) {
        r.delayedStop = false;
        if (r.startRequested) {
            stopServiceLocked(r);
        }
    }

    return null;
}

2.7 realStartServiceLocked()

// frameworks/base/services/core/java/com/android/server/am/ActiveServices.java
private final void realStartServiceLocked(ServiceRecord r,
        ProcessRecord app, boolean execInFg) throws RemoteException {
    if (app.thread == null) {
        throw new RemoteException();
    }

    r.setProcess(app);
    r.restartTime = r.lastActivity = SystemClock.uptimeMillis();

    final boolean newService = app.services.add(r);
    // 调度Service超时检测(前台20秒,后台200秒)
    bumpServiceExecutingLocked(r, execInFg, "create");
    mAm.updateLruProcessLocked(app, false, null);
    updateServiceForegroundLocked(r.app, true);
    mAm.updateOomAdjLocked();

    boolean created = false;
    try {
        synchronized (r.stats.getBatteryStats()) {
            r.stats.startLaunchedLocked();
        }
        mAm.notifyPackageUse(r.serviceInfo.packageName,
                PackageManager.NOTIFY_PACKAGE_USE_SERVICE);
        app.forceProcessStateUpTo(ActivityManager.PROCESS_STATE_SERVICE);
        // 通过Binder调用应用进程创建Service
        app.thread.scheduleCreateService(r, r.serviceInfo,
                mAm.compatibilityInfoForPackageLocked(r.serviceInfo.applicationInfo),
                app.getReportedProcState());
        r.postNotification();
        created = true;
    } catch (DeadObjectException e) {
        mAm.appDiedLocked(app);
        throw e;
    } finally {
        if (!created) {
            // 创建失败清理
            final boolean inDestroying = mDestroyingServices.contains(r);
            serviceDoneExecutingLocked(r, inDestroying, inDestroying);
            if (newService) {
                app.services.remove(r);
                r.setProcess(null);
            }
            if (!inDestroying) {
                scheduleServiceRestartLocked(r, false);
            }
        }
    }

    // 如果Service已绑定,发送绑定回调
    requestServiceBindingsLocked(r, execInFg);

    // 更新Service状态
    updateServiceClientActivitiesLocked(app, null, true);

    // 如果是startService启动,调用onStartCommand
    if (r.startRequested && r.callStart && r.pendingStarts.size() == 0) {
        r.pendingStarts.add(new ServiceRecord.StartItem(r, false, r.makeNextStartId(),
                null, null, 0));
    }

    sendServiceArgsLocked(r, execInFg, true);

    // 前台服务处理
    if (r.delayed) {
        getServiceMapLocked(r.userId).mDelayedStartList.remove(r);
        r.delayed = false;
    }

    if (r.delayedStop) {
        r.delayedStop = false;
        if (r.startRequested) {
            stopServiceLocked(r);
        }
    }
}

2.8 应用进程创建Service

// frameworks/base/core/java/android/app/ActivityThread.java
private class ApplicationThread extends IApplicationThread.Stub {
    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);
    }
}

class H extends Handler {
    public void handleMessage(Message msg) {
        switch (msg.what) {
            case CREATE_SERVICE:
                handleCreateService((CreateServiceData)msg.obj);
                break;
        }
    }
}

private void handleCreateService(CreateServiceData data) {
    // 获取LoadedApk
    LoadedApk packageInfo = getPackageInfoNoCheck(
            data.info.applicationInfo, data.compatInfo);
    Service service = null;
    try {
        // 创建ContextImpl
        ContextImpl context = ContextImpl.createAppContext(this, packageInfo);
        context.setOuterContext(service);

        // 通过反射创建Service实例
        java.lang.ClassLoader cl = packageInfo.getClassLoader();
        service = packageInfo.getAppFactory()
                .instantiateService(cl, data.info.name, data.intent);

        // 创建Application(如果不存在)
        Application app = packageInfo.makeApplication(false, mInstrumentation);

        // 初始化Service
        service.attach(context, this, data.info.name, data.token, app,
                ActivityManager.getService());

        // 调用onCreate()
        service.onCreate();
        mServices.put(data.token, service);

        // 通知AMS创建完成
        try {
            ActivityManager.getService().serviceDoneExecuting(
                    data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0);
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    } catch (Exception e) {
        if (!mInstrumentation.onException(service, e)) {
            throw new RuntimeException(
                    "Unable to create service " + data.info.name
                    + ": " + e.toString(), e);
        }
    }
}

2.9 sendServiceArgsLocked() - 调用onStartCommand

// frameworks/base/services/core/java/com/android/server/am/ActiveServices.java
private final void sendServiceArgsLocked(ServiceRecord r, boolean execInFg,
        boolean oomAdjusted) throws TransactionTooLargeException {
    final int N = r.pendingStarts.size();
    if (N == 0) {
        return;
    }

    ArrayList<ServiceStartArgs> args = new ArrayList<>();

    while (r.pendingStarts.size() > 0) {
        ServiceRecord.StartItem si = r.pendingStarts.remove(0);
        if (si.intent == null && N > 1) {
            // 如果有多个挂起的启动,跳过空Intent
            continue;
        }
        si.deliveredTime = SystemClock.uptimeMillis();
        r.deliveredStarts.add(si);
        si.deliveryCount++;
        if (si.neededGrants != null) {
            mAm.grantUriPermissionUncheckedFromIntentLocked(si.neededGrants,
                    si.getUriPermissionsLocked());
        }
        bumpServiceExecutingLocked(r, execInFg, "start");
        if (!oomAdjusted) {
            oomAdjusted = true;
            mAm.updateOomAdjLocked(r.app, true);
        }
        args.add(new ServiceStartArgs(si.taskRemoved, si.id, si.intent));
    }

    ParceledListSlice<ServiceStartArgs> slice = new ParceledListSlice<>(args);
    slice.setInlineCountLimit(4);
    Exception caughtException = null;
    try {
        // 调用应用进程的onStartCommand
        r.app.thread.scheduleServiceArgs(r, slice);
    } catch (TransactionTooLargeException e) {
        caughtException = e;
    } catch (RemoteException e) {
        caughtException = e;
    } catch (Exception e) {
        caughtException = e;
    }

    if (caughtException != null) {
        // 异常处理
        final boolean inDestroying = mDestroyingServices.contains(r);
        for (int i=0; i<args.size(); i++) {
            serviceDoneExecutingLocked(r, inDestroying, inDestroying);
        }
        if (caughtException instanceof TransactionTooLargeException) {
            throw (TransactionTooLargeException)caughtException;
        }
    }
}

2.10 应用进程调用onStartCommand

// frameworks/base/core/java/android/app/ActivityThread.java
private void handleServiceArgs(ServiceArgsData data) {
    Service s = mServices.get(data.token);
    if (s != null) {
        try {
            if (data.args != null) {
                data.args.setExtrasClassLoader(s.getClassLoader());
                data.args.prepareToEnterProcess();
            }
            int res;
            if (!data.taskRemoved) {
                // 调用onStartCommand
                res = s.onStartCommand(data.args, data.flags, data.startId);
            } else {
                // 任务被移除,调用onTaskRemoved
                s.onTaskRemoved(data.args);
                res = Service.START_TASK_REMOVED_COMPLETE;
            }

            // 确保服务处于活跃状态
            QueuedWork.waitToFinish();

            try {
                // 通知AMS执行完成
                ActivityManager.getService().serviceDoneExecuting(
                        data.token, SERVICE_DONE_EXECUTING_START, data.startId, res);
            } catch (RemoteException e) {
                throw e.rethrowFromSystemServer();
            }
        } catch (Exception e) {
            if (!mInstrumentation.onException(s, e)) {
                throw new RuntimeException(
                        "Unable to start service " + s
                        + " with " + data.args + ": " + e.toString(), e);
            }
        }
    }
}

2.11 startService完整流程图

Service实例 ApplicationThread ActiveServices ActivityManagerService 应用进程 Service实例 ApplicationThread ActiveServices ActivityManagerService 应用进程 alt [进程不存在] startService(intent) startService(IPC) startServiceLocked retrieveServiceLocked解析 bringUpServiceLocked startProcessLocked scheduleCreateService(IPC) handleCreateService new Service() attach() onCreate() serviceDoneExecuting scheduleServiceArgs(IPC) onStartCommand() serviceDoneExecuting

三、bindService绑定流程

3.1 bindService调用入口

// 应用代码
Intent intent = new Intent(this, MyService.class);
bindService(intent, serviceConnection, BIND_AUTO_CREATE);

// ServiceConnection回调
private ServiceConnection serviceConnection = new ServiceConnection() {
    @Override
    public void onServiceConnected(ComponentName name, IBinder service) {
        // 获取Service的Binder对象
        MyService.MyBinder binder = (MyService.MyBinder) service;
        myService = binder.getService();
    }

    @Override
    public void onServiceDisconnected(ComponentName name) {
        myService = null;
    }
};

3.2 ContextImpl.bindService()

// frameworks/base/core/java/android/app/ContextImpl.java
@Override
public boolean bindService(Intent service, ServiceConnection conn, int flags) {
    warnIfCallingFromSystemProcess();
    return bindServiceCommon(service, conn, flags, null, mMainThread.getHandler(), null,
            getUser());
}

private boolean bindServiceCommon(Intent service, ServiceConnection conn, int flags,
        String instanceName, Handler handler, Executor executor, UserHandle user) {
    // 验证ServiceConnection
    if (conn == null) {
        throw new IllegalArgumentException("connection is null");
    }
    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);
        // 调用AMS绑定服务
        int res = ActivityManager.getService().bindService(
            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();
    }
}

关键点

  • ServiceDispatcher将ServiceConnection转换为IServiceConnection Binder接口
  • BIND_AUTO_CREATE标志表示Service不存在时自动创建

3.3 ServiceDispatcher封装

// frameworks/base/core/java/android/app/LoadedApk.java
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) {
            // 创建新的ServiceDispatcher
            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 final Context mContext;
    private final Handler mActivityThread;
    private final int mFlags;

    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, boolean dead)
                throws RemoteException {
            LoadedApk.ServiceDispatcher sd = mDispatcher.get();
            if (sd != null) {
                sd.connected(name, service, dead);
            }
        }
    }

    ServiceDispatcher(ServiceConnection conn,
            Context context, Handler activityThread, int flags) {
        mIServiceConnection = new InnerConnection(this);
        mConnection = conn;
        mContext = context;
        mActivityThread = activityThread;
        mFlags = flags;
    }

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

    public void doConnected(ComponentName name, IBinder service, boolean dead) {
        ServiceDispatcher.ConnectionInfo old;
        ServiceDispatcher.ConnectionInfo info;

        synchronized (this) {
            old = mActiveConnections.get(name);
            if (old != null && old.binder == service) {
                // 已经连接,不需要回调
                return;
            }

            if (service != null) {
                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) {
                    mActiveConnections.remove(name);
                    return;
                }
            } else {
                mActiveConnections.remove(name);
            }

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

        // 回调onServiceConnected
        if (old != null) {
            mConnection.onServiceDisconnected(name);
        }
        if (dead) {
            mConnection.onBindingDied(name);
        }
        if (service != null) {
            mConnection.onServiceConnected(name, service);
        } else {
            mConnection.onNullBinding(name);
        }
    }
}

3.4 ActiveServices.bindServiceLocked()

// frameworks/base/services/core/java/com/android/server/am/ActiveServices.java
int bindServiceLocked(IApplicationThread caller, IBinder token, Intent service,
        String resolvedType, final IServiceConnection connection, int flags,
        String instanceName, String callingPackage, final int userId)
        throws TransactionTooLargeException {

    final ProcessRecord callerApp = mAm.getRecordForAppLocked(caller);
    if (callerApp == null) {
        throw new SecurityException("Unable to find app for caller " + caller);
    }

    ActivityServiceConnectionsHolder<ConnectionRecord> activity = null;
    if (token != null) {
        activity = mAm.mAtmInternal.getServiceConnectionsHolder(token);
        if (activity == null) {
            return 0;
        }
    }

    // 解析Service
    ServiceLookupResult res =
        retrieveServiceLocked(service, instanceName, resolvedType, callingPackage,
                Binder.getCallingPid(), Binder.getCallingUid(), userId, true,
                callerFg, isBindExternal, allowInstant);
    if (res == null) {
        return 0;
    }
    if (res.record == null) {
        return -1;
    }
    ServiceRecord s = res.record;

    // 创建ConnectionRecord
    AppBindRecord b = s.retrieveAppBindingLocked(service, callerApp);
    ConnectionRecord c = new ConnectionRecord(b, activity,
            connection, flags, clientLabel, clientIntent,
            callerApp.uid, callerApp.processName, callingPackage);

    IBinder binder = connection.asBinder();
    ArrayList<ConnectionRecord> clist = s.connections.get(binder);
    if (clist == null) {
        clist = new ArrayList<>();
        s.connections.put(binder, clist);
    }
    clist.add(c);
    b.connections.add(c);
    if (activity != null) {
        activity.addConnection(c);
    }
    clist = mServiceConnections.get(binder);
    if (clist == null) {
        clist = new ArrayList<>();
        mServiceConnections.put(binder, clist);
    }
    clist.add(c);

    // 启动Service(如果需要)
    if ((flags&Context.BIND_AUTO_CREATE) != 0) {
        s.lastActivity = SystemClock.uptimeMillis();
        if (bringUpServiceLocked(s, service.getFlags(), callerFg, false,
                permissionsReviewRequired) != null) {
            return 0;
        }
    }

    // 如果Service已启动,请求绑定
    if (s.app != null && b.intent.received) {
        // Service已运行且已绑定过,直接回调
        try {
            c.conn.connected(s.name, b.intent.binder, false);
        } catch (Exception e) {
            Slog.w(TAG, "Failure sending service " + s.shortInstanceName
                    + " to connection " + c.conn.asBinder()
                    + " (in " + c.binding.client.processName + ")", e);
        }

        // 如果Intent已请求过,不需要再次请求
        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);
    }

    getServiceMapLocked(s.userId).ensureNotStartingBackgroundLocked(s);

    return 1;
}

3.5 requestServiceBindingLocked()

// frameworks/base/services/core/java/com/android/server/am/ActiveServices.java
private final boolean requestServiceBindingLocked(ServiceRecord r, IntentBindRecord i,
        boolean execInFg, boolean rebind) throws TransactionTooLargeException {
    if (r.app == null || r.app.thread == null) {
        // Service进程已死亡
        return false;
    }
    if ((!i.requested || rebind) && i.apps.size() > 0) {
        try {
            bumpServiceExecutingLocked(r, execInFg, "bind");
            r.app.forceProcessStateUpTo(ActivityManager.PROCESS_STATE_SERVICE);
            // 调用Service.onBind()
            r.app.thread.scheduleBindService(r, i.intent.getIntent(), rebind,
                    r.app.getReportedProcState());
            if (!rebind) {
                i.requested = true;
            }
            i.hasBound = true;
            i.doRebind = false;
        } catch (TransactionTooLargeException e) {
            final boolean inDestroying = mDestroyingServices.contains(r);
            serviceDoneExecutingLocked(r, inDestroying, inDestroying);
            throw e;
        } catch (RemoteException e) {
            final boolean inDestroying = mDestroyingServices.contains(r);
            serviceDoneExecutingLocked(r, inDestroying, inDestroying);
            return false;
        }
    }
    return true;
}

3.6 应用进程处理绑定

// frameworks/base/core/java/android/app/ActivityThread.java
private void handleBindService(BindServiceData data) {
    Service s = mServices.get(data.token);
    if (s != null) {
        try {
            data.intent.setExtrasClassLoader(s.getClassLoader());
            data.intent.prepareToEnterProcess();
            try {
                if (!data.rebind) {
                    // 调用onBind()
                    IBinder binder = s.onBind(data.intent);
                    // 将Binder对象返回给AMS
                    ActivityManager.getService().publishService(
                            data.token, data.intent, binder);
                } else {
                    // 调用onRebind()
                    s.onRebind(data.intent);
                    ActivityManager.getService().serviceDoneExecuting(
                            data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0);
                }
            } catch (RemoteException ex) {
                throw ex.rethrowFromSystemServer();
            }
        } catch (Exception e) {
            if (!mInstrumentation.onException(s, e)) {
                throw new RuntimeException(
                        "Unable to bind to service " + s
                        + " with " + data.intent + ": " + e.toString(), e);
            }
        }
    }
}

3.7 publishService返回Binder

// frameworks/base/services/core/java/com/android/server/am/ActiveServices.java
public void publishServiceLocked(ServiceRecord r, Intent intent, IBinder service) {
    final long origId = Binder.clearCallingIdentity();
    try {
        if (r != null) {
            Intent.FilterComparison filter
                    = new Intent.FilterComparison(intent);
            IntentBindRecord b = r.bindings.get(filter);
            if (b != null && !b.received) {
                b.binder = service;
                b.requested = true;
                b.received = true;
                ArrayMap<IBinder, ArrayList<ConnectionRecord>> connections = r.getConnections();
                for (int conni = connections.size() - 1; conni >= 0; conni--) {
                    ArrayList<ConnectionRecord> clist = connections.valueAt(conni);
                    for (int i=0; i<clist.size(); i++) {
                        ConnectionRecord c = clist.get(i);
                        if (!filter.equals(c.binding.intent.intent)) {
                            continue;
                        }
                        try {
                            // 回调客户端的onServiceConnected
                            c.conn.connected(r.name, service, false);
                        } catch (Exception e) {
                            Slog.w(TAG, "Failure sending service " + r.shortInstanceName
                                    + " to connection " + c.conn.asBinder()
                                    + " (in " + c.binding.client.processName + ")", e);
                        }
                    }
                }
            }

            serviceDoneExecutingLocked(r, mDestroyingServices.contains(r), false);
        }
    } finally {
        Binder.restoreCallingIdentity(origId);
    }
}

3.8 bindService完整流程图

Service实例 Service进程 ActiveServices ActivityManagerService 客户端进程 Service实例 Service进程 ActiveServices ActivityManagerService 客户端进程 alt [Service未运行] bindService(intent, conn, flags) bindService(IPC) bindServiceLocked 创建ConnectionRecord 创建Service进程 onCreate() scheduleBindService(IPC) onBind() publishService(binder) publishServiceLocked connected(name, binder)(IPC) onServiceConnected(name, binder)

四、AIDL跨进程通信

4.1 AIDL接口定义

// IMyService.aidl
package com.example.service;

interface IMyService {
    String getData();
    void setData(String data);
    void registerCallback(IMyCallback callback);
}

// IMyCallback.aidl
package com.example.service;

interface IMyCallback {
    void onDataChanged(String data);
}

4.2 Service端实现

public class MyService extends Service {
    private final RemoteCallbackList<IMyCallback> callbacks = new RemoteCallbackList<>();
    private String data = "Initial Data";

    private final IMyService.Stub binder = new IMyService.Stub() {
        @Override
        public String getData() throws RemoteException {
            return data;
        }

        @Override
        public void setData(String newData) throws RemoteException {
            data = newData;
            // 通知所有注册的回调
            final int N = callbacks.beginBroadcast();
            for (int i = 0; i < N; i++) {
                try {
                    callbacks.getBroadcastItem(i).onDataChanged(data);
                } catch (RemoteException e) {
                    // 客户端可能已死亡
                }
            }
            callbacks.finishBroadcast();
        }

        @Override
        public void registerCallback(IMyCallback callback) throws RemoteException {
            if (callback != null) {
                callbacks.register(callback);
            }
        }
    };

    @Override
    public IBinder onBind(Intent intent) {
        return binder;
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        callbacks.kill();
    }
}

4.3 客户端使用

public class ClientActivity extends AppCompatActivity {
    private IMyService myService;
    private boolean isBound = false;

    private final IMyCallback.Stub callback = new IMyCallback.Stub() {
        @Override
        public void onDataChanged(String data) throws RemoteException {
            // 注意:此方法在Binder线程调用,需要切换到主线程
            runOnUiThread(() -> {
                Toast.makeText(ClientActivity.this, "Data: " + data, Toast.LENGTH_SHORT).show();
            });
        }
    };

    private ServiceConnection connection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            myService = IMyService.Stub.asInterface(service);
            isBound = true;
            try {
                // 注册回调
                myService.registerCallback(callback);
                // 获取数据
                String data = myService.getData();
                Log.d("Client", "Initial data: " + data);
            } catch (RemoteException e) {
                e.printStackTrace();
            }
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
            myService = null;
            isBound = false;
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_client);

        // 绑定Service
        Intent intent = new Intent();
        intent.setComponent(new ComponentName(
                "com.example.service",
                "com.example.service.MyService"));
        bindService(intent, connection, BIND_AUTO_CREATE);
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        if (isBound) {
            unbindService(connection);
            isBound = false;
        }
    }

    public void updateData(String newData) {
        if (isBound && myService != null) {
            try {
                myService.setData(newData);
            } catch (RemoteException e) {
                e.printStackTrace();
            }
        }
    }
}

4.4 Binder通信机制

Proxy

Stub

回调

Callback

客户端进程

Binder驱动

Service进程

Service实现


五、前台服务

5.1 前台服务的重要性

Android 8.0+对后台服务进行了严格限制,前台服务是保证长时间运行的关键。

5.2 启动前台服务

public class MusicService extends Service {
    private static final int NOTIFICATION_ID = 1;

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        // 创建通知渠道(Android 8.0+)
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            NotificationChannel channel = new NotificationChannel(
                    "music_channel",
                    "Music Playback",
                    NotificationManager.IMPORTANCE_LOW);
            NotificationManager manager = getSystemService(NotificationManager.class);
            manager.createNotificationChannel(channel);
        }

        // 创建通知
        Intent notificationIntent = new Intent(this, MainActivity.class);
        PendingIntent pendingIntent = PendingIntent.getActivity(
                this, 0, notificationIntent, PendingIntent.FLAG_IMMUTABLE);

        Notification notification = new NotificationCompat.Builder(this, "music_channel")
                .setContentTitle("Music Player")
                .setContentText("Playing music")
                .setSmallIcon(R.drawable.ic_music)
                .setContentIntent(pendingIntent)
                .build();

        // 启动前台服务
        startForeground(NOTIFICATION_ID, notification);

        return START_STICKY;
    }

    @Override
    public void onDestroy() {
        // 停止前台服务
        stopForeground(true);
        super.onDestroy();
    }

    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }
}

5.3 前台服务权限声明

<!-- AndroidManifest.xml -->
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />

<!-- Android 9.0+ 需要指定前台服务类型 -->
<service
    android:name=".MusicService"
    android:foregroundServiceType="mediaPlayback"
    android:exported="false" />

5.4 前台服务类型(Android 10+)

<!-- 前台服务类型 -->
<service
    android:name=".LocationService"
    android:foregroundServiceType="location" />

<!-- 多种类型组合 -->
<service
    android:name=".MyService"
    android:foregroundServiceType="location|camera" />

可用类型

  • camera:相机
  • dataSync:数据同步
  • location:位置
  • mediaPlayback:媒体播放
  • mediaProjection:屏幕投影
  • microphone:麦克风
  • phoneCall:电话
  • connectedDevice:连接设备

六、IntentService

6.1 IntentService原理

IntentService是Service的子类,自动在工作线程处理Intent,处理完成后自动停止。

// frameworks/base/core/java/android/app/IntentService.java
public abstract class IntentService extends Service {
    private volatile Looper mServiceLooper;
    private volatile ServiceHandler mServiceHandler;
    private String mName;
    private boolean mRedelivery;

    private final class ServiceHandler extends Handler {
        public ServiceHandler(Looper looper) {
            super(looper);
        }

        @Override
        public void handleMessage(Message msg) {
            // 在工作线程处理Intent
            onHandleIntent((Intent)msg.obj);
            // 处理完成后停止服务
            stopSelf(msg.arg1);
        }
    }

    public IntentService(String name) {
        super();
        mName = name;
    }

    @Override
    public void onCreate() {
        super.onCreate();
        // 创建工作线程
        HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
        thread.start();

        mServiceLooper = thread.getLooper();
        mServiceHandler = new ServiceHandler(mServiceLooper);
    }

    @Override
    public int onStartCommand(@Nullable Intent intent, int flags, int startId) {
        onStart(intent, startId);
        return mRedelivery ? START_REDELIVER_INTENT : START_NOT_STICKY;
    }

    @Override
    public void onStart(@Nullable Intent intent, int startId) {
        Message msg = mServiceHandler.obtainMessage();
        msg.arg1 = startId;
        msg.obj = intent;
        mServiceHandler.sendMessage(msg);
    }

    @Override
    public void onDestroy() {
        mServiceLooper.quit();
    }

    @Override
    @Nullable
    public IBinder onBind(Intent intent) {
        return null;
    }

    // 子类实现此方法处理Intent
    @WorkerThread
    protected abstract void onHandleIntent(@Nullable Intent intent);
}

6.2 IntentService使用示例

public class DownloadService extends IntentService {
    public DownloadService() {
        super("DownloadService");
    }

    @Override
    protected void onHandleIntent(@Nullable Intent intent) {
        if (intent != null) {
            String url = intent.getStringExtra("url");
            String filename = intent.getStringExtra("filename");
            // 在工作线程执行下载
            downloadFile(url, filename);
        }
    }

    private void downloadFile(String url, String filename) {
        try {
            // 下载逻辑
            Thread.sleep(5000); // 模拟下载
            // 下载完成通知
            sendBroadcast(new Intent("DOWNLOAD_COMPLETE"));
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

七、某IoT项目实战经验

7.1 项目背景

某IoT智能家居项目需要维持与设备的长连接,处理设备状态上报和远程控制指令。

7.2 架构设计

bindService

MainActivity

DeviceService

Connection Manager

MQTT Client

IoT设备

Message Handler

设备状态数据库

UI更新通知

7.3 核心代码实现

public class DeviceService extends Service {
    private final IBinder binder = new LocalBinder();
    private MqttClient mqttClient;
    private final RemoteCallbackList<IDeviceCallback> callbacks = new RemoteCallbackList<>();

    public class LocalBinder extends Binder {
        public DeviceService getService() {
            return DeviceService.this;
        }
    }

    @Override
    public void onCreate() {
        super.onCreate();
        // 初始化MQTT连接
        initMqttConnection();
        // 启动为前台服务
        startForegroundService();
    }

    private void startForegroundService() {
        // 创建通知
        Notification notification = createNotification();
        startForeground(1, notification);
    }

    private void initMqttConnection() {
        try {
            String broker = "tcp://mqtt.example.com:1883";
            String clientId = "android_" + UUID.randomUUID().toString();
            mqttClient = new MqttClient(broker, clientId, new MemoryPersistence());

            MqttConnectOptions options = new MqttConnectOptions();
            options.setCleanSession(true);
            options.setKeepAliveInterval(60);
            options.setAutomaticReconnect(true);

            mqttClient.setCallback(new MqttCallback() {
                @Override
                public void connectionLost(Throwable cause) {
                    // 连接断开,自动重连
                    notifyConnectionStatus(false);
                }

                @Override
                public void messageArrived(String topic, MqttMessage message) throws Exception {
                    // 处理设备消息
                    handleDeviceMessage(topic, new String(message.getPayload()));
                }

                @Override
                public void deliveryComplete(IMqttDeliveryToken token) {
                    // 消息发送完成
                }
            });

            mqttClient.connect(options);
            // 订阅设备主题
            mqttClient.subscribe("devices/+/status", 1);
            notifyConnectionStatus(true);

        } catch (MqttException e) {
            e.printStackTrace();
        }
    }

    private void handleDeviceMessage(String topic, String payload) {
        // 解析设备消息
        try {
            JSONObject json = new JSONObject(payload);
            String deviceId = json.getString("deviceId");
            String status = json.getString("status");

            // 更新数据库
            updateDeviceStatus(deviceId, status);

            // 通知所有回调
            final int N = callbacks.beginBroadcast();
            for (int i = 0; i < N; i++) {
                try {
                    callbacks.getBroadcastItem(i).onDeviceStatusChanged(deviceId, status);
                } catch (RemoteException e) {
                    // 客户端可能已死亡
                }
            }
            callbacks.finishBroadcast();

        } catch (JSONException e) {
            e.printStackTrace();
        }
    }

    public void controlDevice(String deviceId, String command) {
        try {
            JSONObject json = new JSONObject();
            json.put("deviceId", deviceId);
            json.put("command", command);
            json.put("timestamp", System.currentTimeMillis());

            String topic = "devices/" + deviceId + "/control";
            mqttClient.publish(topic, json.toString().getBytes(), 1, false);

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public void registerCallback(IDeviceCallback callback) {
        if (callback != null) {
            callbacks.register(callback);
        }
    }

    public void unregisterCallback(IDeviceCallback callback) {
        if (callback != null) {
            callbacks.unregister(callback);
        }
    }

    @Override
    public IBinder onBind(Intent intent) {
        return binder;
    }

    @Override
    public void onDestroy() {
        try {
            if (mqttClient != null && mqttClient.isConnected()) {
                mqttClient.disconnect();
            }
        } catch (MqttException e) {
            e.printStackTrace();
        }
        callbacks.kill();
        super.onDestroy();
    }
}

7.4 优化要点

  1. 前台服务保活:避免被系统杀死
  2. 自动重连机制:网络断开时自动重连
  3. 心跳保持:MQTT KeepAlive机制
  4. 数据持久化:重要数据存储到数据库
  5. 内存优化:及时释放不用的资源

八、Service ANR分析与避免

8.1 ANR触发条件

  • Service的onCreate、onStartCommand、onBind在主线程执行超过20秒
  • 前台服务超时20秒,后台服务超时200秒

8.2 ANR日志分析

# 获取ANR日志
adb pull /data/anr/traces.txt

# traces.txt内容示例
----- pid 12345 at 2024-01-01 10:00:00 -----
Cmd line: com.example.app
...
"main" prio=5 tid=1 Native
  | group="main" sCount=1 dsCount=0 flags=1 obj=0x74b7f000 self=0x7f8c001200
  | sysTid=12345 nice=0 cgrp=default sched=0/0 handle=0x7f8c400000
  | state=S schedstat=( 1000000000 200000000 100 ) utm=80 stm=20 core=0 HZ=100
  | stack=0x7ff0000000-0x7ff0002000 stackSize=8MB
  at java.lang.Thread.sleep(Native method)
  at com.example.MyService.onCreate(MyService.java:50)
  ...

8.3 避免ANR的最佳实践

public class MyService extends Service {
    private ExecutorService executor = Executors.newCachedThreadPool();

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        // 不要在主线程执行耗时操作
        executor.execute(() -> {
            try {
                // 耗时操作
                performHeavyTask();
            } finally {
                // 任务完成后停止服务
                stopSelf(startId);
            }
        });

        return START_NOT_STICKY;
    }

    private void performHeavyTask() {
        // 网络请求、数据库操作、文件IO等
    }

    @Override
    public void onDestroy() {
        executor.shutdown();
        super.onDestroy();
    }
}

九、性能优化建议

9.1 合理选择启动方式

场景 推荐方式
后台任务,不需要交互 startService + IntentService
需要与Service交互 bindService
长时间运行 前台Service
定时任务 WorkManager(推荐)或AlarmManager

9.2 避免内存泄漏

public class MyService extends Service {
    // 错误:静态引用导致内存泄漏
    private static Context sContext;

    // 正确:使用弱引用
    private static WeakReference<Context> sContextRef;

    @Override
    public void onCreate() {
        super.onCreate();
        // 使用ApplicationContext,避免泄漏Activity
        sContextRef = new WeakReference<>(getApplicationContext());
    }
}

9.3 进程保活策略

  1. 前台服务:最可靠的保活方式
  2. 提升进程优先级:通过startForeground()
  3. 监听系统广播:在合适时机重启Service
  4. JobScheduler/WorkManager:系统级任务调度
// 使用WorkManager替代Service(推荐)
public class UploadWorker extends Worker {
    public UploadWorker(@NonNull Context context, @NonNull WorkerParameters params) {
        super(context, params);
    }

    @NonNull
    @Override
    public Result doWork() {
        // 执行后台任务
        uploadData();
        return Result.success();
    }

    private void uploadData() {
        // 上传逻辑
    }
}

// 调度任务
Constraints constraints = new Constraints.Builder()
        .setRequiredNetworkType(NetworkType.CONNECTED)
        .setRequiresBatteryNotLow(true)
        .build();

OneTimeWorkRequest uploadWork = new OneTimeWorkRequest.Builder(UploadWorker.class)
        .setConstraints(constraints)
        .build();

WorkManager.getInstance(context).enqueue(uploadWork);

十、总结

10.1 核心要点

  1. startService:独立生命周期,适合后台任务
  2. bindService:绑定生命周期,适合交互场景
  3. AIDL:跨进程通信的标准方式
  4. 前台服务:长时间运行的必要条件
  5. ANR避免:主线程不执行耗时操作

10.2 完整流程对比

对比项 startService bindService
生命周期 独立于调用者 依赖调用者
停止方式 stopService/stopSelf unbindService
通信方式 Intent传递数据 Binder双向通信
回调方法 onCreate→onStartCommand onCreate→onBind
典型场景 后台下载、日志上传 跨进程调用、实时数据

10.3 最佳实践建议

  1. Android 8.0+优先使用前台服务
  2. 定时任务优先使用WorkManager
  3. 避免在Service中执行长时间操作
  4. 合理管理Service生命周期
  5. 注意内存泄漏和ANR问题

参考资料

  1. AOSP源码:https://cs.android.com/
  2. Android官方文档:https://developer.android.com/guide/components/services
  3. 《Android进阶解密》 - 刘望舒
  4. MQTT官方文档:https://mqtt.org/

文章版本:基于Android 10 (API Level 29) AOSP源码
最后更新:2024年
作者声明:本文基于公开AOSP源码和某IoT项目经验(已去敏),不涉及商业机密

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐