美文网首页
Service源码解析之启动Service

Service源码解析之启动Service

作者: AntCoding | 来源:发表于2019-03-17 15:41 被阅读0次

概括

Service是Android的四大组件之一,它是一个没有前台展示页面但可以一直在后台运行的组件.因为Service跟Activity一样都是运行UI线程的既使Service没有前台页面也尽量不要在Service中执行耗时操作,除非在Service中声明子线程.
这篇文章从Service的启动入手进行源码分析讲解此为上篇,下篇将讲述Service的Binder过程.

启动Service

1.对于Service的解析我们需要从 startService(Intent service) 开始
public class ContextWrapper extends Context {
    Context mBase;​
   ​@Override
   public ComponentName startService(Intent service) {
       return mBase.startService(service);
   }
}​
2.此处可以看到直接调入到ContextWrapper类中startActivity方法函数中(注意: 我们知道四大组件中由于Activity需要界面绘制所以他继承的是一个带主题的ContextWapper即ContextThemeWapper;而Service是没有页面绘制的所以它继承的是ContextWrapper,此处的调用直接调入到了Service的父类中)
public abstract class Context {
    ​@Nullable
    public abstract ComponentName startService(Intent service);
}​
3.在ContextWrapper中并没有功能的实现,而直接进入到ContextWrapper的父类Context的startService(Intent service)函数方法中,但是Context是个抽象类没有对其进行实现;这该如何是好!
还记得我们在分析Activity启动过程那篇文章中提到的(Activity初始化中的相关操作都是交由ContextImpl去实现的​),即ContextImpl是Context的实现类ContextImpl下继续分析startService(Intent service)方法函数
class ContextImpl extends Context {
   @Override
   public ComponentName startService(Intent service) {
      //若系统进程直接调用,会输出警告级Log日志
      warnIfCallingFromSystemProcess();
      return startServiceCommon(service, false, mUser);
  }
  private ComponentName startServiceCommon(Intent service, boolean requireForeground,
        UserHandle user) {
    try {
        //检查Service Intent​,若无指定Service Intent发送的包名 21API之前会给出警告"此隐式意图不安全" ,21API之后会抛出异常"必须明确意图"
        validateServiceIntent(service);
        //​准备让Intent离开程序进程
        service.prepareToLeaveProcess(this);
        //通过AMS,startService​并返回一个ComponetName类型的值
        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();
    }
  }​​
​​}​
4.既然我们获取了AMS,并且调用了AMS中的satrtService函数方法,那么我们就去看看它里面的实现:
@Override
public ComponentName startService(IApplicationThread caller, Intent service,
        String resolvedType, boolean requireForeground, 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 + " fg=" + requireForeground);
    synchronized(this) {
        //获取​当前进程ID
        final int callingPid = Binder.getCallingPid();
        //获取分配给进程的Linux UID​
        final int callingUid = Binder.getCallingUid();
        //重置当前线程的IPC标识​
        final long origId = Binder.clearCallingIdentity();
        ComponentName res;
        try {
         ​    //AMS向下继续调用,并将上面获取到的ID和标识传入进去
            res = mServices.startServiceLocked(caller, service,
                    resolvedType, callingPid, callingUid,
                    requireForeground, callingPackage, userId);
        } finally {
            Binder.restoreCallingIdentity(origId);
        }
        return res;
    }
}
5. AMS在startSevice方法中并没有实现功能,而是获取了一些参数,继续向下调用
ComponentName startServiceLocked(IApplicationThread caller, Intent service, String resolvedType,
        int callingPid, int callingUid, boolean fgRequired, String callingPackage, final int userId)
        throws TransactionTooLargeException {
    ...
     //对服务进行检索​
    ServiceLookupResult res =
        retrieveServiceLocked(service, resolvedType, callingPackage,
                callingPid, callingUid, userId, true, callerFg, false);
    if (res == null) {
        return null;
    }
    //判断服务检索检索记录是否为Null​
    if (res.record == null) {
        return new ComponentName("!", res.permission != null
                ? res.permission : "private to package");
    }
    ServiceRecord r = res.record;
    if (!mAm.mUserController.exists(r.userId)) {
        Slog.w(TAG, "Trying to start service with non-existent user! " + r.userId);
        return null;
    }
   ServiceRecord r = res.record;​
  ​ final ServiceMap smap = getServiceMapLocked(r.userId);
    ...
    ​ 
    ComponentName cmp = startServiceInnerLocked(smap, service, r, callerFg, addToStarting);
    return cmp;
}
6. 上面这段段代码好大一坨,然而无关键的实现还得继续前行 startServiceInnerLocked(smap, service, r, callerFg, addToStarting)
ComponentName startServiceInnerLocked(ServiceMap smap, Intent service, ServiceRecord r, boolean callerFg, boolean addToStarting) throws TransactionTooLargeException {
           ... 
           String error = bringUpServiceLocked(r, service.getFlags(), callerFg, false, false); 
           ... 
          return r.name
}

7.继续调用进入bringUpServiceLocked方法函数
private final void realStartServiceLocked(ServiceRecord r,
        ProcessRecord app, boolean execInFg) throws RemoteException {
      if (!isolated) {
    app = mAm.getProcessRecordLocked(procName, r.appInfo.uid, false);
    if (DEBUG_MU) Slog.v(TAG_MU, "bringUpServiceLocked: appInfo.uid=" + r.appInfo.uid
                + " app=" + app);
    if (app != null && app.thread != null) {
        try {
            app.addPackage(r.appInfo.packageName, r.appInfo.versionCode, mAm.mProcessStats);
            //​发现一个方法函数,这个名在起的好真切啊"真实开启服务锁",但愿是最后了吧!
            realStartServiceLocked(r, app, execInFg);
            return null;
        } catch (TransactionTooLargeException e) {
            throw e;
        } catch (RemoteException e) {
            Slog.w(TAG, "Exception when starting service " + r.shortName, e);
        }
        // If a dead object exception was thrown -- fall through to
        // restart the application.
    } 
 } 
     
​​}​​
8.看看 realStartServiceLocked方法函数它的实现吧!
private final void realStartServiceLocked(ServiceRecord r,
        ProcessRecord app, boolean execInFg) throws RemoteException {
      boolean created = false;
try {
    if (LOG_SERVICE_START_STOP) {
        String nameTerm;
        int lastPeriod = r.shortName.lastIndexOf('.');
        nameTerm = lastPeriod >= 0 ? r.shortName.substring(lastPeriod) : r.shortName;
        EventLogTags.writeAmCreateService(
                r.userId, System.identityHashCode(r), nameTerm, r.app.uid, r.app.pid);
    }
    synchronized (r.stats.getBatteryStats()) {
        r.stats.startLaunchedLocked();
    }
    mAm.notifyPackageUse(r.serviceInfo.packageName,
                         PackageManager.NOTIFY_PACKAGE_USE_SERVICE);
    app.forceProcessStateUpTo(ActivityManager.PROCESS_STATE_SERVICE);
     //终于找到正主了,正式进入ApplicationThread中创建Service​  <1>创建启动
    app.thread.scheduleCreateService(r, r.serviceInfo,
            mAm.compatibilityInfoForPackageLocked(r.serviceInfo.applicationInfo),
            app.repProcState);
    r.postNotification();
    created = true;
} catch (DeadObjectException e) {
    Slog.w(TAG, "Application dead when creating service " + r);
    mAm.appDiedLocked(app);
    throw e;
} finally {
    if (!created) {
        // Keep the executeNesting count accurate.
        final boolean inDestroying = mDestroyingServices.contains(r);
        serviceDoneExecutingLocked(r, inDestroying, inDestroying);
        // Cleanup.
        if (newService) {
            app.services.remove(r);
            r.app = null;
        }
        // Retry.
        if (!inDestroying) {
            scheduleServiceRestartLocked(r, false);
        }
    }
}
 if (r.whitelistManager) {
    app.whitelistManager = true;
}​
//Servie绑定过程
requestServiceBindingsLocked(r, execInFg);
updateServiceClientActivitiesLocked(app, null, true);​​
...
sendServiceArgsLocked(r, execInFg, true); // ​​调取Service的onStrart方法
if (r.delayedStop) {
    // Oh and hey we've already been asked to stop!
    r.delayedStop = false;
    if (r.startRequested) {
        if (DEBUG_DELAYED_STARTS) Slog.v(TAG_SERVICE,
                "Applying delayed stop (from start): " + r);
        stopServiceLocked(r);  //
    }
}
​​
}​​
9. 通过调用 app.thread.scheduleCreateService方法函数 源码来到了ActivityThread内部类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);
}​
10.这里发了一个Handler消息,会交由H类的handleMessage做处理
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;
11.最终交由 handleCreateService函数实现对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;
    //通过类加载器,实例化Service​
    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);
         //创建一个对应Service的ContextImpl的对象​
        ContextImpl context = ContextImpl.createAppContext(this, packageInfo);
         //设置外部上下文环境​
        context.setOuterContext(service);
         //创建一个application​
        Application app = packageInfo.makeApplication(false, mInstrumentation);
        //初始化Service​
        service.attach(context, this, data.info.name, data.token, app,
                ActivityManager.getService());
         //调用Service的onCreate生命周期​
        service.onCreate();
        mServices.put(data.token, service);
        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);
        }
    }
}

由此我们便将Service启动起来了,下篇我将来讲解Service的Binder过程!

This ALL! Thanks EveryBody!

相关文章

网友评论

      本文标题:Service源码解析之启动Service

      本文链接:https://www.haomeiwen.com/subject/nndumqtx.html