基于N源码Service启动分析
来源:互联网 发布:.eps用什么软件打开 编辑:程序博客网 时间:2024/06/05 22:33
前面分析了应用内部Activity的启动过程,其实如果是应用第一个Activity的启动,流程上还会多一些创建进程和ActivityThread的过程。Service同样也是如此,如果是应用内部启动服务,且没有配置android:process的话,默认就在应用进程中启动,下面我们就配置android:process=“:remote”,让服务在另一个进程中启动。
private void startServiceTest(){Intent intent = new Intent("com.android.wuliq.service");startService(intent);}
接着进入ContextImpl.java
public ComponentName startService(Intent service) { warnIfCallingFromSystemProcess(); return startServiceCommon(service, mUser); } @Override public boolean stopService(Intent service) { warnIfCallingFromSystemProcess(); return stopServiceCommon(service, mUser); } private ComponentName startServiceCommon(Intent service, UserHandle user) { try { validateServiceIntent(service); service.prepareToLeaveProcess(this); ComponentName cn = ActivityManagerNative.getDefault().startService( mMainThread.getApplicationThread(), service, service.resolveTypeIfNeeded( getContentResolver()), 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()); } } return cn; } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } }
可以看到跟Activity启动很类似,调用ActivityManagerNative.getDefault().startService进行跨进程通讯。getDefault()获取本地代理ActivityManagerProxy对象,调用ActivityManagerProxy中的startService方法:
public ComponentName startService(IApplicationThread caller, Intent service, String resolvedType, String callingPackage, int userId) throws RemoteException { Parcel data = Parcel.obtain(); Parcel reply = Parcel.obtain(); data.writeInterfaceToken(IActivityManager.descriptor); data.writeStrongBinder(caller != null ? caller.asBinder() : null); service.writeToParcel(data, 0); data.writeString(resolvedType); data.writeString(callingPackage); data.writeInt(userId); mRemote.transact(START_SERVICE_TRANSACTION, data, reply, 0); reply.readException(); ComponentName res = ComponentName.readFromParcel(reply); data.recycle(); reply.recycle(); return res; }
用远程binder对象mRemote调用transact会通过底层binder驱动转到远程服务的中间者stub(ActivityManagerNative):
case START_SERVICE_TRANSACTION: { data.enforceInterface(IActivityManager.descriptor); IBinder b = data.readStrongBinder(); IApplicationThread app = ApplicationThreadNative.asInterface(b); Intent service = Intent.CREATOR.createFromParcel(data); String resolvedType = data.readString(); String callingPackage = data.readString(); int userId = data.readInt(); ComponentName cn = startService(app, service, resolvedType, callingPackage, userId); reply.writeNoException(); ComponentName.writeToParcel(cn, reply); return true; }
可以看到远程这边通过IApplicationThread app = ApplicationThreadNative.asInterface(b);获取本地代理ApplicationThreadProxy,后面从服务端调用客户端接口需要用到它。
接着调用到服务端实现者AMS:
public ComponentName startService(IApplicationThread caller, Intent service, String resolvedType, String callingPackage, int userId) throws TransactionTooLargeException {ComponentName res = mServices.startServiceLocked(caller, service, resolvedType, callingPid, callingUid, callingPackage, userId);}
这里调用了ActiveServices.java中的startServiceLocked方法:
ComponentName startServiceLocked(IApplicationThread caller, Intent service, String resolvedType, int callingPid, int callingUid, String callingPackage, final int userId) throws TransactionTooLargeException {ServiceLookupResult res = retrieveServiceLocked(service, resolvedType, callingPackage, callingPid, callingUid, userId, true, callerFg, false);ServiceRecord r = res.record;return startServiceInnerLocked(smap, service, r, callerFg, addToStarting);}
这里会通过retrieveServiceLocked去检索AndroidManifest.xml文件并将服务信息存储在ServiceRecord中。接着跳转到startServiceInnerLocked,里面又跳转到bringUpServiceLocked函数:
private String bringUpServiceLocked(ServiceRecord r, int intentFlags, boolean execInFg, boolean whileRestarting, boolean permissionsReviewRequired) throws TransactionTooLargeException {ProcessRecord app;app = mAm.getProcessRecordLocked(procName, r.appInfo.uid, false);if (app != null && app.thread != null) { realStartServiceLocked(r, app, execInFg);} if (app == null && !permissionsReviewRequired) { 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; } }}
这里的mAm为ActivityManagerService类型,如果获取进程信息不为空,则调用realStartServiceLocked启动服务。这里我们要求在另一个进程中启动,因此进程并未创建,为空。所以调用AMS的startProcessLocked方法,开启进程:
private final void startProcessLocked(ProcessRecord app, String hostingType, String hostingNameStr, String abiOverride, String entryPoint, String[] entryPointArgs) { if (entryPoint == null) entryPoint = "android.app.ActivityThread"; Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "Start proc: " + app.processName); checkTime(startTime, "startProcess: asking zygote to start proc"); Process.ProcessStartResult startResult = Process.start(entryPoint, app.processName, uid, uid, gids, debugFlags, mountExternal, app.info.targetSdkVersion, app.info.seinfo, requiredAbi, instructionSet, app.info.dataDir, entryPointArgs);this.mPidsSelfLocked.put(startResult.pid, app);}
这里调用Process.start函数创建了一个新的进程,指定新的进程执行android.app.ActivityThread类。最后将表示这个新进程的ProcessRecord保存在mPidSelfLocked列表中。
新建一个进程后,然后导入android.app.ActivityThread这个类,然后执行它的main函数:
public static void main(String[] args) { Looper.prepareMainLooper(); ActivityThread thread = new ActivityThread(); thread.attach(false); if (sMainThreadHandler == null) { sMainThreadHandler = thread.getHandler(); }Looper.loop();}
可以看到这里创建了ActivityThread对象,并创建looper和消息队列。主线程的消息队列就是在这里创建的。在Android应用程序中,每一个进程对应一个ActivityThread实例,这里调用ActivityThread.attach函数进一步处理:
private void attach(boolean system) { final IActivityManager mgr = ActivityManagerNative.getDefault(); try { mgr.attachApplication(mAppThread); } catch (RemoteException ex) { throw ex.rethrowFromSystemServer(); }}
可以看到,又是跨进程访问,由经验得知,直接进入AMS的attachApplication函数:
private final boolean attachApplicationLocked(IApplicationThread thread, int pid) {ProcessRecord app;app = mPidsSelfLocked.get(pid);mServices.attachApplicationLocked(app, processName);}
获取之前保存的进程信息,接着调用ActiveServices.java的attachApplicationLocked函数:
boolean attachApplicationLocked(ProcessRecord proc, String processName) throws RemoteException { 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)) { // We were waiting for this service to start, but it is actually no // longer needed. This could happen because bringDownServiceIfNeeded // won't bring down a service that is pending... so now the pending // is done, so let's drop it. bringDownServiceLocked(sr); } }}
获取之前保存的服务信息,调用realStartServiceLocked启动服务:
private final void realStartServiceLocked(ServiceRecord r, ProcessRecord app, boolean execInFg) throws RemoteException { app.thread.scheduleCreateService(r, r.serviceInfo, mAm.compatibilityInfoForPackageLocked(r.serviceInfo.applicationInfo), app.repProcState);sendServiceArgsLocked(r, execInFg, true);}
这里的app.thread就是前面attachApplication的时候获取的客户端的本地代理ApplicationThreadProxy,调用它的scheduleCreateService会跨进程到客户端的ApplicationThread中的scheduleCreateService:
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); }
下面的流程就跟Activity的启动很相似了。
case CREATE_SERVICE: Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, ("serviceCreate: " + String.valueOf(msg.obj))); handleCreateService((CreateServiceData)msg.obj); Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); break;
private void handleCreateService(CreateServiceData data) { java.lang.ClassLoader cl = packageInfo.getClassLoader(); service = (Service) cl.loadClass(data.info.name).newInstance(); 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();}可以看到这里获取ClassLoader创建了Service,并创建了ContextImpl、Application等,attach给service,最后调用onCreate()。
至于onStartCommand是在什么时候调用呢,跟踪代码发现在ActiveServices.java中app.thread.scheduleCreateService执行完后,调用了sendServiceArgsLocked(r, execInFg, true);函数,也是跨进程到客户端,发消息调用onStart。
至此,这个自定义的服务就启动起来了。
这样,Android系统在新进程中启动服务的过程就分析完成了,虽然很复杂,但是条理很清晰。它通过三次Binder进程间通信完成了服务的启动过程,分别是:
一. 从主进程调用到ActivityManagerService进程中,完成新进程的创建;
二. 从新进程调用到ActivityManagerService进程中,获取要在新进程启动的服务的相关信息;
三. 从ActivityManagerService进程又回到新进程中,最终将服务启动起来。
- 基于N源码Service启动分析
- 基于N源码的Activity的启动过程分析
- Nova Service启动源码分析
- android源码分析 Service的启动过程
- Android四大组件Service启动源码分析
- bind远程Service 过程分析,基于4.4.3源码
- Service启动流程源码分析之startService(一)
- Service启动流程源码分析之bindService(二)
- Service启动过程and新进程创建全过程源码分析
- Service启动流程源码分析(一):startService
- Android Service的启动流程源码分析(8.0)
- 基于N源码的广播注册和发送流程分析
- 基于N源码的ContentProvider调用流程分析
- solrcloud集群启动管理过程基于源码的分析
- 点击桌面图标Activity启动流程分析 - 基于Android5.0源码
- u-boot源码分析 --- 启动第二阶段 ,基于2410 启动代码 分析
- u-boot源码分析 --- 启动第二阶段 ,基于2410 启动代码 分析
- [android源码分析]bluetoothd service的启动的总体流程分析
- 四书 - 中庸
- iOS TableViewCell 底下线显示不全解决方案
- 评价,星星
- 学习MongoDB--(4-2):MongoDB查询(数组、内嵌文档和$where)
- countdown-min.js使用 倒计时
- 基于N源码Service启动分析
- **c++ stl 顺序容器: begin(),end()和front(),back()区别和使用**
- 函数模板
- SystemUI的下拉状态栏分析
- 学习Markdown基本语法笔记
- 【C++】typedef
- NPOI使用手册
- SAP财务中国本土好内容
- 通过QT_DEBUG_PLUGINS调试连接PostgreSQL/MySQL时driver not loaded问题