四大组件之Service
来源:互联网 发布:cad平面设计软件 编辑:程序博客网 时间:2024/05/17 01:08
四大组件第二重要的就是Service了,有两种方式来启动,startService和BindService,看了一下和Activity似乎是一致的流程,只是Activity是有关联个Window来显示界面,Service没有。
方式1 StartService()
在Activity中找到这个方法,发现实际上只调用ContextWrapper里的函数代码如下
@Override public ComponentName startService(Intent service) { return mBase.startService(service); }
使用的是mBase这个Context来start的,看一下这个变量是哪里来的,追溯的Activity初始化的时候。
performLaunchActivity的时候会创建Activity,之后会调用attch来建立Activity必要联系,再attch中有这样的调用
attachBaseContext(context);这里的context就是mBase,回到performLaunchActivity,
Context appContext = createBaseContextForActivity(r, activity);
创建的appContext这个Context,最后其实使用的是ContextImpl这个类。
static ContextImpl createActivityContext(ActivityThread mainThread, LoadedApk packageInfo, IBinder activityToken, int displayId, Configuration overrideConfiguration) { if (packageInfo == null) throw new IllegalArgumentException("packageInfo"); return new ContextImpl(null, mainThread, packageInfo, activityToken, null, 0, null, overrideConfiguration, displayId); }
在这个类中,可以看到startService的代码
@Override public ComponentName startService(Intent service) { warnIfCallingFromSystemProcess(); return startServiceCommon(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(); } }
代码中, ActivityManagerNative.getDefault()其实就是获得了ActivityManagerService,去观察一下那里是怎么启动的。
ActivityManagerService.java
@Override public ComponentName startService(IApplicationThread caller, Intent service, String resolvedType, String callingPackage, int userId) throws TransactionTooLargeException { enforceNotIsolatedCaller("startService"); // Refuse possible leaked file descriptors if (service != null && service.hasFileDescriptors() == true) { throw new IllegalArgumentException("File descriptors passed in Intent"); } if (callingPackage == null) { throw new IllegalArgumentException("callingPackage cannot be null"); } if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "startService: " + service + " type=" + resolvedType); synchronized(this) { final int callingPid = Binder.getCallingPid(); final int callingUid = Binder.getCallingUid(); final long origId = Binder.clearCallingIdentity(); ComponentName res = mServices.startServiceLocked(caller, service, resolvedType, callingPid, callingUid, callingPackage, userId); Binder.restoreCallingIdentity(origId); return res; } }
ActiveServices.java
startServiceLocked()//这里可能有一些查询的工作,看到取出一个map中services,有可能是使用action方式启动需要查询,没有仔细看。
startServiceInnerLocked()
bringUpServiceLocked()
realStartServiceLocked(r, app, execInFg)
app.thread.scheduleCreateService(r, r.serviceInfo, mAm.compatibilityInfoForPackageLocked(r.serviceInfo.applicationInfo), app.repProcState);
调用了AppThread(是ActivityThread的内部类)的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); }
将Service的信息通过messge发送的H(主线程Handler),看一下处理
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;
在handleCreatService中才真正实例化,建立必要联系,进入Service的生命周期代码如下
private void handleCreateService(CreateServiceData data) { // If we are getting ready to gc after going to the background, well // we are back active so skip it. 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) { if (!mInstrumentation.onException(service, e)) { throw new RuntimeException( "Unable to instantiate service " + data.info.name + ": " + e.toString(), e); } } try { if (localLOGV) Slog.v(TAG, "Creating service " + data.info.name); 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) { throw e.rethrowFromSystemServer(); } } catch (Exception e) { if (!mInstrumentation.onException(service, e)) { throw new RuntimeException( "Unable to create service " + data.info.name + ": " + e.toString(), e); } } }
看到使用java 的newInstance这种方式实例化Service如下
java.lang.ClassLoader cl = packageInfo.getClassLoader(); service = (Service) cl.loadClass(data.info.name).newInstance();
比且调用了 onCreate()回调,整个流程的activity很相似。
方式2 bindService()启动
一开始也是使用mBase.bindService(service, conn, flags)这中方式,同上面一致,经过ActiviyMangerService到ActiveServices,流程就差不多了。
这种方式下主要想分析一下是怎么调用Service的onBind()返回一个Binder的。
ContextImp.java
bindServiceCommon()这个方法中,
sd = mPackageInfo.getServiceDispatcher(conn, getOuterContext(), handler, flags);
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) { sd = new ServiceDispatcher(c, context, handler, flags); if (map == null) { map = new ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher>(); mServices.put(context, map); } map.put(c, sd); } else { sd.validate(context, handler); } return sd.getIServiceConnection(); } }
在这个方法中返回一个接口,这个接口是aidl接口,查看了一下和正常的aidl生成的文件一致,有Bind ,还有binder的内部类Proxy,还有转发回调onTransact。
mService:一个应用中所有的,ServiceConnection对象,和ServiceDispatcher对象的对应关系map。
ServiceDispatcher:建立起ServiceConnection和InnerConnection的关系,InnerConnection代码如下
将这一对的ServiceConnection和ServiceDispatcher装到map中。
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) throws RemoteException { LoadedApk.ServiceDispatcher sd = mDispatcher.get(); if (sd != null) { sd.connected(name, service); } } }
简单来说,它调用了connect的时候调用了ServiceConnect的onServiceConnected方法。
关于存取对应关系的代码好复杂,不去看了,各种Map....看一下最后怎么调用的吧,
ActivityThread.java
private void handleBindService(BindServiceData data) { Service s = mServices.get(data.token); if (DEBUG_SERVICE) Slog.v(TAG, "handleBindService s=" + s + " rebind=" + data.rebind); if (s != null) { try { data.intent.setExtrasClassLoader(s.getClassLoader()); data.intent.prepareToEnterProcess(); try { if (!data.rebind) { IBinder binder = s.onBind(data.intent); ActivityManagerNative.getDefault().publishService( data.token, data.intent, binder); } else { s.onRebind(data.intent); ActivityManagerNative.getDefault().serviceDoneExecuting( data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0); } ensureJitEnabled(); } 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); } } } }
onBind()返回Binder,之后使用ActivityManagerService的PublisService(),又调用了publishServiceLocked。
void publishServiceLocked(ServiceRecord r, Intent intent, IBinder service) { final long origId = Binder.clearCallingIdentity(); try { if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "PUBLISHING " + r + " " + intent + ": " + service); 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; for (int conni=r.connections.size()-1; conni>=0; conni--) { ArrayList<ConnectionRecord> clist = r.connections.valueAt(conni); for (int i=0; i<clist.size(); i++) { ConnectionRecord c = clist.get(i); if (!filter.equals(c.binding.intent.intent)) { if (DEBUG_SERVICE) Slog.v( TAG_SERVICE, "Not publishing to: " + c); if (DEBUG_SERVICE) Slog.v( TAG_SERVICE, "Bound intent: " + c.binding.intent.intent); if (DEBUG_SERVICE) Slog.v( TAG_SERVICE, "Published intent: " + intent); continue; } if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "Publishing to: " + c); try { c.conn.connected(r.name, service); } catch (Exception e) { Slog.w(TAG, "Failure sending service " + r.name + " to connection " + c.conn.asBinder() + " (in " + c.binding.client.processName + ")", e); } } } } serviceDoneExecutingLocked(r, mDestroyingServices.contains(r), false); } } finally { Binder.restoreCallingIdentity(origId); } }
ConnectionRecord c = clist.get(i);
这句简单理解为从列表中取了出来,
c.conn.connected(r.name, service);
调用了这个方法onServiceConnected()。
以后工作深入在研究吧,现在也用不到。
- 四大组件之Service
- 四大组件之Service
- 四大组件之Service
- 四大组件之Service
- 四大组件之Service
- 四大组件之Service
- 四大组件之Service
- 四大组件之service
- 四大组件之Service
- 四大组件之Service
- 四大组件之Service
- 四大组件之Service
- 四大组件之Service
- 四大组件之Service
- 四大组件之Service
- 四大组件之Service
- 四大组件之Service
- 四大组件之service
- 程序编译后的结构和动态编译重定位,程序编译知识
- Android下使用jni实现基于opencv与dlib的68关键点检测
- 设计模式-创建者模式总结
- HDU 6026
- Log4j1升级Log4j2实战
- 四大组件之Service
- Cookie的使用----MVC
- 复杂链表的复制
- org.springframework.web.util.NestedServletException: Request processing fail
- 使用Hystrix实现自动降级与依赖隔离
- Html5 Fundamental
- CentOS下安装Python3.5
- 消息队列探秘-Kafka、RabbitMQ对比
- API接口的安全验证