Android service startup process Complete Analysis _android

Source: Internet
Author: User

When you first started learning service, you thought it was a thread encapsulation, and you could perform time-consuming operations. In fact, service is run in the main thread. Direct execution of time-consuming operations can block the main thread. A long time straight ANR.

We know that service can perform some background tasks, is the background task is not a time-consuming task, background and time-consuming is different oh.
This makes it easy to think of music players, which use service in weather forecasts. Of course, if you want to perform time-consuming operations in your service, it's OK to open a thread.

There are two kinds of running state of service, starting state and binding state, two states can be together.
Starting a service simply calls the StartService method of the context and passes in a intent. It looks as if it's easy to say, because Android does a lot of encapsulation for the convenience of developers. So do you really have to learn how service is started? What is the preparation for the service before the OnCreate method callback?

To get a rough picture, the gray background box is the method in the same class, as shown in the following figure:

Then from the source point of view to analyze the service startup process.

Of course, starting from the StartService method of the context, the implementation class of the context is Contextimpl, then we see the Contextimpl StartService method, as follows:

@Override public
componentname startservice (Intent service) {
  warnifcallingfromsystemprocess ();
  return Startservicecommon (service, muser);


Will go to the Startservicecommon method, then follow the Startservicecommon method to see.

Private ComponentName Startservicecommon (Intent service, Userhandle user) {
  try {
    validateserviceintent ( Service);
    Service.preparetoleaveprocess ();
    ComponentName cn = Activitymanagernative.getdefault (). StartService (
      mmainthread.getapplicationthread (), Service, service.resolvetypeifneeded (
            getcontentresolver ()), Getoppackagename (), User.getidentifier ());

  The code omits return

    CN.
  } catch (RemoteException e) {
    throw new RuntimeException ("Failure from System", e);
  }
}

You can see the StartService method that invoked the Activitymanagernative.getdefault () to start the Service,activitymanagernative.getdefault () is Activitymanagerservice, referred to as AMS.

So now the process of starting the service is transferred to the Activitymanagerservice, we are concerned about the StartService method of Activitymanagerservice, as follows:

@Override public
componentname startservice (iapplicationthread caller, Intent service,
    String Resolvedtype, String callingpackage, int userId)
    throws transactiontoolargeexception {

   //code omitted

  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;
  }


In the above code, the Activeservices startservicelocked method is invoked, and the service startup process is now transferred from the AMS to the activeservices.

Continue to follow up the Activeservices startservicelocked method as follows:

ComponentName startservicelocked (iapplicationthread caller, Intent service, String resolvedtype,
    int callingpid, int Callinguid, String callingpackage, int userId)
    throws transactiontoolargeexception {

  //code omitted

  Servicelookupresult res =
    retrieveservicelocked (service, Resolvedtype, Callingpackage,
        callingpid, Callinguid, UserId, True, CALLERFG);

  Code omitted


  Servicerecord r = Res.record;

  Code omitted return

  startserviceinnerlocked (SMAP, service, R, CALLERFG, addtostarting);
}

The Startserviceinnerlocked method is also invoked in the Startservicelocked method,

Let's see the Startserviceinnerlocked method,

ComponentName startserviceinnerlocked (servicemap SMAP, Intent service, Servicerecord R,
    Boolean CALLERFG, Boolean addtostarting) throws Transactiontoolargeexception {
  processstats.servicestate stracker = R.gettracker ();
  if (Stracker!= null) {
    stracker.setstarted (True, mAm.mProcessStats.getMemFactorLocked (), r.lastactivity);
  R.callstart = false;
  Synchronized (R.stats.getbatterystats ()) {
    r.stats.startrunninglocked ();
  }
  String error = bringupservicelocked (R, Service.getflags (), CALLERFG, false);

  Code omitted return

  r.name;
}

The Bringupservicelocked method is called internally by the Startserviceinnerlocked method, and the startup process is almost out of activeservices. Continue to see the Bringupservicelocked method. As follows:

Private final String bringupservicelocked (Servicerecord r, int intentflags, Boolean execinfg,
    Boolean whilerestarting) throws Transactiontoolargeexception {

    //code omitted

    if (app!= null && app.thread!= null) {
   try {
        app.addpackage (r.appinfo.packagename, R.appinfo.versioncode, mam.mprocessstats);
        Realstartservicelocked (r, app, EXECINFG);
        return null;
      } 

    Code omits return

    null;
}

Omit most if judgment, believe that the eagle-eyed you must have found the core method, that is
Realstartservicelocked, yes, looking at a name is like actually starting a service. Then without further ado follow up and explore it. As follows:

Private final void realstartservicelocked (Servicerecord R,
    Processrecord app, Boolean execinfg) throws remoteexception {

  //code omitted

  Boolean created = false;
  try {

    //code omitted
    app.forceprocessstateupto (activitymanager.process_state_service);
    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;
  } 

  The code omits

  sendserviceargslocked (R, Execinfg, true);

  Code omitted

}

Got it. App.thread called Schedulecreateservice to start the service, and App.thread is a applicationthread and an internal class of activitythread. This is the main thread.
Then we probe into the Schedulecreateservice method of Applicationthread. As follows:

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);
}

Wraps the information for the service component that was started, and then sends a message. We pay attention to this create_service message.

public void Handlemessage (message msg) {

    //code omitted case

    Create_service:
      trace.tracebegin (Trace.trace_ Tag_activity_manager, "Servicecreate");
      Handlecreateservice ((createservicedata) msg.obj);
      Trace.traceend (Trace.trace_tag_activity_manager);
      break;

    Code omitted

}

This message is received in the Handlemessage method, and then the Handlecreateservice method is invoked to follow the Handlecreateservice probe:

private void Handlecreateservice (Createservicedata data) {//If we are getting ready to GC after going to the Backgrou
  nd, down//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 ("Un
    Able to instantiate service "+ Data.info.name +": "+ e.tostring (), E);

    The 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);
    The catch (RemoteException e) {//Nothing todo.
        } catch (Exception e) {if (!minstrumentation.onexception (service, E)) {throw new RuntimeException (
    "Unable to create service" + Data.info.name + ":" + e.tostring (), E);

 }
  }
}

Finally, this method is very core. A little bit of analysis

First get to a loadedapk object, get a class loader through this loadedapk object, and use this class loader to create the service. As follows:

Java.lang.ClassLoader cl = Packageinfo.getclassloader ();
Service = (Service) cl.loadclass (data.info.name). newinstance ();

The Contextimpl Createappcontext method is then invoked to create a Contextimpl object.

The loadedapk Makeapplication method is then invoked to create the application, which is the following creation process:

Public Application Makeapplication (Boolean forcedefaultappclass, instrumentation instrumentation) {if (mApplicatio
  n!= null) {return mapplication;

  } application app = null;
  String appclass = mapplicationinfo.classname; if (Forcedefaultappclass | | (Appclass = null))
  {Appclass = "android.app.Application";
    try {java.lang.ClassLoader cl = getClassLoader ();
    if (!mpackagename.equals ("Android")) {Initializejavacontextclassloader ();
    } Contextimpl Appcontext = Contextimpl.createappcontext (Mactivitythread, this);
    App = MActivityThread.mInstrumentation.newApplication (cl, Appclass, Appcontext);
  Appcontext.setoutercontext (APP); 
        The catch (Exception e) {if (!mactivitythread.minstrumentation.onexception (app, E)) {throw new RuntimeException (
    "Unable to instantiate application" + Appclass + ":" + e.tostring (), E);
  } mActivityThread.mAllApplications.add (APP);

  Mapplication = app; if (Instrumentation!= null) {try {instrumentation.callapplicationoncreate (APP); catch (Exception e) {if (!instrumentation.onexception (app, E)) {throw new RuntimeException ("U
      Nable to create Application "+ App.getclass (). GetName () +": "+ e.tostring (), E);
  }}//Rewrite the R ' constants ' for all library APKs.
  sparsearray<string> packageidentifiers = getassets (mactivitythread). Getassignedpackageidentifiers ();
  Final int N = Packageidentifiers.size ();
    for (int i = 0; i < N; i++) {final int id = Packageidentifiers.keyat (i);
    if (id = = 0X01 | | | id = = 0x7f) {continue;
  } rewritervalues (getClassLoader (), Packageidentifiers.valueat (i), id);
return app;

 }

Of course application is only one, from the above code can also be seen.

After returning to see the Handlecreateservice method, the service calls the Attach method associated with Contextimpl and application, etc.

The last service recalls the OnCreate method,

Service.oncreate ();
Mservices.put (Data.token, service);

The service was added to a list for management.

This service started up, the above is the service start process.

You may also want to know how the Onstartcommand method was recalled? May be careful you find in the Realstartservicelocked method of Activeservices, there is also a sendserviceargslocked method. Yes, that's the entrance.

So let's follow up the sendserviceargslocked method and see how the Onstartcommand method is recalled.

Private final void sendserviceargslocked (Servicerecord R, Boolean execinfg,
    boolean oomadjusted) throws transactiontoolargeexception {
  final int N = R.pendingstarts.size ();

    The code omits

    try {

    //code omitted

      R.app.thread.scheduleserviceargs (R, si.taskremoved, Si.id, Flags, si.intent);
    } catch (Transactiontoolargeexception e) {
      if (debug_service) slog.v (Tag_service, Transaction too large:intent=)
          + si.intent);
      Caughtexception = e;
    } catch (RemoteException e) {
      //Remote process gone ... we'll let the normal cleanup take care to this.
      if (debug_service) slog.v (Tag_service, "crashed while sending args:" + R);
      Caughtexception = e;
    } 

    Code omitted
}

You can see that the Onstartcommand method callback process is very similar to the OnCreate method and will go to App.thread. Then follow up on Applicationthread's Scheduleserviceargs now.
You may also have guessed that it should encapsulate some service information, and then send a message handlemessage receive. Yes, the source code is as follows:

Public final void Scheduleserviceargs (IBinder token, boolean taskremoved, int startid,
  int flags, Intent args) {
  S Erviceargsdata s = new Serviceargsdata ();
  S.token = token;
  s.taskremoved = taskremoved;
  S.startid = Startid;
  S.flags = flags;
  S.args = args;

  SendMessage (H.service_args, s);
}

public void Handlemessage (message msg) {

    //code omitted case

    Service_args:
      trace.tracebegin (trace.trace_tag_ Activity_manager, "Servicestart");
      Handleserviceargs ((serviceargsdata) msg.obj);
      Trace.traceend (Trace.trace_tag_activity_manager);
      break;

    Code omitted
}

Gee, it really is. The answer should be in the Handleserviceargs method, so hurriedly look, the source code is as follows:

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 (); try {activitymanagernative.getdefault (). servicedoneexecuting (Data.token, Service_done_executing_star
      T, Data.startid, res);
      The catch (RemoteException e) {//Nothing todo.
    } ensurejitenabled (); The catch (Exception e) {if (!minstrumentation.onexception (S, e)) {throw new RuntimeException ("
      Unable to start service "+ S +" with "+ Data.args +": "+ e.tostring (), E); }
    }
  }
}

 

You can see a callback to the Onstartcommand method.

The above is the service START process source code analysis.

From this, I understand the service of the start-up process, the ability to read the source also improved, the analysis of the source code when I do not have the ability to put every variable, every method to understand, I focus on are some key words, such as this article is the start Ah, service AH. There's a feeling that this is the right thing to do. Of course, if you get caught in the alley also want to pocket out.

Such analysis can also be able to ascertain the overall process, for details, and so I have a solid foundation in the study.

The above is the entire content of this article, I hope to help you learn, but also hope that we support the cloud habitat community.

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.