startService 分析--之二

3,服务所在进程

服务所在进程调用流程图如下,


3.1服务已启动

服务已启动,则直接调用sendServiceArgsLocked方法,

private final void sendServiceArgsLocked(ServiceRecord r, boolean execInFg,
            boolean oomAdjusted) throws TransactionTooLargeException {
        final int N = r.pendingStarts.size(); 

        while (r.pendingStarts.size() > 0) {
            Exception caughtException = null;
            ServiceRecord.StartItem si;
            try {
                si = r.pendingStarts.remove(0);
               •••
                si.deliveredTime = SystemClock.uptimeMillis();
                r.deliveredStarts.add(si);
                si.deliveryCount++;
               ••• 
            r.app.thread.scheduleServiceArgs(r, si.taskRemoved, si.id, flags, si.intent);
            } catch (TransactionTooLargeException e) { 
                caughtException = e;
            } catch (RemoteException e) { 
                caughtException = e;
            } catch (Exception e) {
                Slog.w(TAG, "Unexpected exception", e);
                caughtException = e;
            }

            if (caughtException != null) {
                // Keep nesting count correct
                final boolean inDestroying = mDestroyingServices.contains(r);
                serviceDoneExecutingLocked(r, inDestroying, inDestroying);
                if (caughtException instanceof TransactionTooLargeException) {
                    throw (TransactionTooLargeException)caughtException;
                }
                break;
            }
        }
    }

这里也涉及到跨进程通信,由AMS所在进程转移到要启动的服务所在进程A。仔细研究ApplicationThreadNative.java源码,

r.app.thread指ApplicationThreadProxy对象,利用Binder机制,转移到进程A主线程(ActivityThread)当中继续执行. 

ApplicationThreadNative类和ApplicationThreadProxy类实现了IApplicationThread接口,而ApplicationThreadNative类,

所以ApplicationThreadNative类分别运行于AMS进程以及服务所在进程,这种设计在framework源码中很常见。

scheduleServiceArgs方法如下,

public final void scheduleServiceArgs(IBinder token, boolean taskRemoved, int startId,
            int flags ,Intent args) {
            ServiceArgsData s = new ServiceArgsData();
            s.token = token;
            s.taskRemoved = taskRemoved;
            s.startId = startId;
            s.flags = flags;
            s.args = args;

            sendMessage(H.SERVICE_ARGS, s);
        }

scheduleServiceArgs只是向该主线程发送了一个消息,

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) {
                    res = s.onStartCommand(data.args, data.flags, data.startId);
                } else {
                    s.onTaskRemoved(data.args);
                    res = Service.START_TASK_REMOVED_COMPLETE;
                }

                QueuedWork.waitToFinish();

               •••
            } catch (Exception e) {
               •••
            }
        }
    }

跨进程的调用一般首先向主线程发送消息,切换到主线程中执行。

终于看到调用服务的onStartCommand方法了, 由于方法运行于主线程中,所以不要在onCreate()、onStart()里执行耗时的操作。

3.2 启动服务

启动服务会调用realStartServiceLocked方法,和上一小节的过程完全一样,也是跨进程通信,发送消息,最后调用利用发射机制构造

服务对象,调用服务的onCreate方法.

private void handleCreateService(CreateServiceData data) { 
        unscheduleGcIdler();

        LoadedApk packageInfo = getPackageInfoNoCheck(
                data.info.applicationInfo, data.compatInfo);
        Service service = null;
        try {
            // 利用反射机制构造服务对象
            java.lang.ClassLoader cl = packageInfo.getClassLoader();
            service = (Service) cl.loadClass(data.info.name).newInstance();
        } catch (Exception e) {
            •••
        }

        try {
            ContextImpl context = ContextImpl.createAppContext(this, packageInfo);
            context.setOuterContext(service);

            Application app = packageInfo.makeApplication(false, mInstrumentation);
            service.attach(context, this, data.info.name, data.token, app,
                    ActivityManagerNative.getDefault());
            service.onCreate();
            mServices.put(data.token, service);
            try {
                ActivityManagerNative.getDefault().serviceDoneExecuting(
                        data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0);
            } catch (RemoteException e) {
                // nothing to do.
            }
        } catch (Exception e) {
          •••
        }
    }

在realStartServiceLocked方法中首先利用反射构造service对象,然后调用sendServiceArgsLocked方法。

sendServiceArgsLocked方法见上个小节。

3.3 启动apk,然后启动服务

服务所在的apk未启动,则调用AMS的startProcessLocked方法,apk详细的启动流程就不论述了,完成apk的启动之后,

在attachApplicationLocked方法中,会依次启动四大组件中的activity,service和broadcast。

private final boolean attachApplicationLocked(IApplicationThread thread,
            int pid) {
        •••
if (normalMode) {
            try {
                if (mStackSupervisor.attachApplicationLocked(app)) { // 启动activity
                    didSomething = true;
                }
            } catch (Exception e) {
                Slog.wtf(TAG, "Exception thrown launching activities in " + app, e);
                badApp = true;
            }
        }

        // Find any services that should be running in this process...
        if (!badApp) {
            try {
                didSomething |= mServices.attachApplicationLocked(app, processName);
                 // 启动service
            } catch (Exception e) {
                Slog.wtf(TAG, "Exception thrown starting services in " + app, e);
                badApp = true;
            }
        }

        // Check if a next-broadcast receiver is in this process...
        if (!badApp && isPendingBroadcastProcessLocked(pid)) {
            try {
                didSomething |= sendPendingBroadcastsLocked(app); // 启动
            } catch (Exception e) {
                // If the app died trying to launch the receiver we declare it 'bad'
                Slog.wtf(TAG, "Exception thrown dispatching broadcasts in " + app, e);
                badApp = true;
            }
        }
}

再看attachApplicationLocked方法,依然会调用realStartServiceLocked方法完成最后的服务启动。

boolean attachApplicationLocked(ProcessRecord proc, String processName)
            throws RemoteException {
        boolean didSomething = false;
        // Collect any services that are waiting for this process to come up.
        if (mPendingServices.size() > 0) {
            ServiceRecord sr = null;
            try {
                for (int i=0; i<mPendingServices.size(); i++) {
                    sr = mPendingServices.get(i);
                    if (proc != sr.isolatedProc && (proc.uid != sr.appInfo.uid
                            || !processName.equals(sr.processName))) {
                        continue;
                    }

                    mPendingServices.remove(i);
                    i--;
                    proc.addPackage(sr.appInfo.packageName, sr.appInfo.versionCode,
                            mAm.mProcessStats);
                    realStartServiceLocked(sr, proc, sr.createdFromFg);
                    didSomething = true;
                    if (!isServiceNeeded(sr, false, false)) {
                        •••
                        bringDownServiceLocked(sr);
                    }
                }
            } catch (RemoteException e) {
                •••
            }
        }
•••
}

因此,如果服务所在的apk未启动,会首先启动apk,然后启动服务。

其实,service的流程和activity流程几乎相同,跨进程调用完全相同。

这里涉及到2个跨进程通信:

1,从apk到AMS。ActivityManagerProxy是AMS的在客户端的代理。

2,从AMS到apk。ApplicationThreadProxy,是ApplicationThread在服务器端的代理,负责和客户端的ApplicationThread通讯。

AMS就是通过该代理与ActivityThread进行通信的。ApplicationThread是ActivityThread的内部类。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值