Activity Manager

The Activity Manager service (com.palm.activitymanager) acts as a traffic cop for Activities (apps, services, tasks, network flows, etc.) running on the device, balancing Activity priorities and system resources to optimize the user's experience. The Activity Manager has the following goals:

In this Section:

See also: Activity Manager Data Types

 


Activity Manager Features

Activity Manager features include:

  • Prioritization—Activities should be created for any non-trivial use of system resources (i.e., CPU, the network). Apps and services can assign an Activity priority level property. The Activity Manager prioritizes Activities based on this and Activities' use of system resources to optimize the user's experience. Foreground Activities are given normal priority; background Activities are given a low priority and run as resources allow.

    You can set an Activity's priority with the Type object, which is an Activity object sub-property.

  • Services run when needed—To conserve system resources, services should run only when needed. Services should not remain running while subscribed to other services such as the TIL (Telephony Interface Layer) or db8 (JSON database), waiting for events or the network to begin work or to communicate outside the device. The Activity Manager does not implement this capability, but it does facilitate it—services and their Activities can use the Activity Manager to subscribe to other services on their behalf and monitor for responses, invoking a callback when a specified event has occurred. While waiting, services can exit, returning resources to the device until the service is again needed.

  • Scheduling and alignment—Activities can be scheduled to run at a specific time or at a particular interval. Activities can be scheduled to run as a background Activity in the future if not needed immediately.
    To reduce how often the device is suspended and restarted, the Activity Manager batches Activities scheduled to run at approximately the same interval. See the Schedule data type for more information.

  • Persistence—Using db8 state storage, Activities can persist across a device reboot. They can be atomically updated and re-scheduled to avoid being lost due to version updating, device crashes, or lost service. Use the Type object's "persist" flag to set this.

  • Requirements prior to running are met—The Activity Manager can ensure that power-state, network access, telephony, battery and other pre-conditions are met before an Activity runs. In addition, the Activity Manager can send out update notices if these pre-conditions change while the Activity is running. See the Requirements data type for more information.

  • Triggers—Activities with triggers do not run until an event occurs on a subscribed method. The Activity Manager can subscribe on behalf of the Activity creator and invoke the specified callback when a trigger event fires. This allows the service to exit and let the Activity Manager wait on its behalf.

    See the Triggers data type for more information.
  • Complete-and-Restart Activities—When a service finishes processing an Activity, it can request the Activity Manager to restart the Activity with updated schedule, triggers, requirements, and callbacks. See the complete API for more information.

  • Power Control—The Activity Manager can ensure the device remains powered while an Activity is running. It can also debounce power, allowing the device to remain powered for a short time waiting for a new task to start. For example, in the case where a network sync service sent out a request and is waiting on an imminent response. In this case, it is better to wait since it takes less power than having the device suspend and restart.

    Your service can request this functionality using the Type object's "power" and "powerDebounce" properties.

  • Standardized control—The Activity Manager provides a standardized interface for controlling (start, stop, pause, and cancel) activity lifecycle.

 


Activity Participants

A running Activity must have a parent. Initially, that would be the service or app that creates it. In addition, Activities can have subscribers which include the Activity's parent, potential adopters and others wishing to monitor the Activity. Subscribers are services or apps that are sent Activity event notifications (start, stop, etc., see Activity Events for a complete list). Adopters are subscribers who can also take over as an Activity's parent. They register their willingness to do this with the adopt method. Apps or services can subscribe to an Activity through either the create, adopt, or monitor methods.

If an Activity loses its parent, and there are no waiting adopters, it is canceled unless marked as persistent or explicit, and all subscribers are sent "cancel" events. When this happens, adopters have the opportunity to take over as the parent and keep the Activity alive. However, it is cancelled if no app or service adopts the Activity during that time. An Activity with a callback can briefly run without a parent while the callback is invoked; the Activity Manager waits for a specified time to see if the app or service adopts the Activity. If not adopted after that time, the Activity is canceled. If an Activity is marked as being persistent or explicit, it is restarted.

 


Activity Manager Methods (API)

You can call Activity Manager methods asynchronously through the serviceRequest function which takes 2 parameters:

  • The Activity Manager URI (Uniform Resource Identifier)
  • A JSON (JavaScript Object Notation) object containing parameters, callback functions, and other data.

For example:

this.controller.serviceRequest("palm://com.palm.activitymanager/", {
   method: "complete",
   parameters: {
                 "activityId": 876
   },
   onSuccess: function(){ Mojo.Log.info("complete success"); },
   onFailure: function(){ Mojo.Log.info("complete failure"); }
});

You can also use the new Foundation library API for calling Palm services. Palm's JavaScript Foundation libraries are a loadable framework that both Mojo and JavaScript service applications can use.

For example:

var libraries = MojoLoader.require({ name: "foundations", version: "1.0" });
var PalmCall = libraries["foundations"].Comms.PalmCall;
PalmCall.call("palm://com.palm.activitymanager/", "addFocus", {"srcActivityID": 876, "targetActivityID": 345 });

Using Foundations also requires your app to have the following two tags in your index.html file:

<script src="/usr/palm/frameworks/mojo/mojo.js" type="text/javascript" x-mojo-version="1"></script> 
<script src="/usr/palm/frameworks/mojoloader.js" type="text/javascript"></script>

Depending on outcome, both calls return a JSON result indicating success or failure. Your code can then parse the result. Your app needs to take into account the call's asynchronous nature (results may be delayed) and not block user interaction while awaiting results.

For more information on calling services such as the Activity Manager, see Services Overiew and Services API.

About JSON

JSON is a lightweight data-interchange text format based on a subset of the JavaScript programming language that is easy for humans to read and write and for machines to parse and generate. Like XML, JSON contains name/value pair collections and ordered list of values (i.e., arrays).

For more information on JSON, see the following websites:

A primer on how JSON data objects are formatted is beyond the scope of this document—consult the two links above for more information. However, in brief:

  • Curly brackets ('{', '}') are used to enclose objects.
  • Angle brackets ('[', ']') are used to enclose arrays.
  • Colons (':') are used as delimiters in name/value pairs.
  • Quotes (") are used for string values. Numeric values are not quoted.

Activity Manager Public Methods

Method Description
adopt Adopt an Activity, registering willingness to take over as parent.
cancel End an Activity immediately, allowing little or no time for clean-up.
complete End an Activity with option to restart with new attributes.
create Create an Activity.
getDetails Get details about an Activity, including associations.
monitor Get Activity state, with option to subscribe to future updates.
release Allows parent to end an Activity, allowing time for adopters to take over as the parent and let the Activity continue.
start Starts an Activity, with an option to force it to run.
stop End an Activity, allowing some time for clean-up.

 


adopt

Registers an app's or service's willingness to take over as the Activity's parent.

If your app can wait for an unavailable Activity (not released) to become available, then set the "wait" flag to true. If it is, and the Activity is valid (exists and is not exiting), the call should succeed. If it cannot wait, and the Activity is valid but cannot be adopted, then the call fails. The adopted return flag indicates a successful or failed adoption.

If not immediately adopted and waiting is requested, the "orphan" event informs the adopter that they are the new Activity parent.

An example where adoption makes sense is an app that allocates a separate Activity for a sync, and passes that Activity to a service to use. The service should adopt the Activity and be ready to take over in the event the app exits before the service is done syncing. Otherwise, it receives a "cancel" event and should exit immediately. The service should wait until the adopt (or monitor) call returns successfully before beginning Activity work. If adopt or monitor fails, it indicates the caller has quit or closed the Activity and the request should not be processed. The Service should continue to process incoming events on their subscription to the Activity.

If the service did not call adopt to indicate to the Activity Manager its willingness to take over as the parent, it should be prepared to stop work for the Activity and unsubscribe if it receives a "cancel" event. Otherwise, if it receives the "orphan" event indicating the parent has unsubscribed and the service is now the parent, then it should use complete when finished to inform the Activity Manager before unsubscribing.

Syntax

{
  "activityId"     : int | "activityName" : string,
  "wait"           : boolean,
  "subscribe"      : boolean,
  "detailedEvents" : boolean
}

Parameters

Argument Required Type Description
activityId No int Activity ID. Either this, or "activityName" is required.
activityName No string Activity name. Either this, or "activityId" is required.
wait Yes boolean Wait for Activity to be released flag.
subscribe Yes boolean Flag to subscribe to Activity and receive Activity events.
detailedEvents Yes boolean Flag to have the Activity Manager generate "update" events when the state of an Activity's requirement changes.

Returns

Argument Type Description
returnValue boolean true (success) or false (failure).
adopted boolean true (adopted) or false (not adopted)

Example

this.controller.serviceRequest("palm://com.palm.activitymanager/", {
   method: "adopt",
   parameters: {
                 "activityId"     : 876,
                 "wait"           : true,
                 "subscribe"      : true,
                 "detailedEvents" : false                                 
   },
   onSuccess: function(e){ Mojo.Log.info("adopt success, adopted="+e.adopted); },
   onFailure: function(e){ Mojo.Log.info("adopt failure"); }
});

 


cancel

Terminates the specified Activity and sends a "cancel" event to all subscribers. This call should succeed if the Activity exists and is not already exiting.

This is different from the stop method in that the Activity should take little or no time to clean up. For example, this might matter for an email sync service that needs more time to finish downloading a large email attachment. On a "cancel", it should immediately abort the download, clean up, and exit. On a "stop", it should finish downloading the attachment in some reasonable amount of time, say, 10-15 seconds. Note, however, that specific time limits are not currently enforced, though this could change.

Syntax

{
  "activityId"  : int | "activityName" : string
}

Parameter

Argument Required Type Description
activityId No int Activity ID. Either this, or "activityName" is required.
activityName No string Activity name. Either this, or "activityId" is required.

Returns

Argument Type Description
returnValue boolean true (success) or false (failure).

Example

this.controller.serviceRequest("palm://com.palm.activitymanager/", {
   method: "cancel",
   parameters: {"activityId": 17},
   onSuccess: function(e) { Mojo.Log.info("cancel success");},
   onFailure: function(e) { Mojo.Log.info("cancel failure");}
});

 


complete

An Activity's parent can use this method to end the Activity and optionally restart it with new attributes. If there are other subscribers, they are sent a "complete" event.

If restart is requested, the Activity is optionally updated with any new Callback, Schedule, Requirements, or Trigger data and returned to the queued state. Specifying false for any of those properties removes the property completely. For any properties not specified, current properties are used.

If the Activity is persistent (specified with the persist flag in the Type object), the db8 database is updated before the call returns.

Syntax

    {
        "activityId"   : int | "activityName" : string,
        "restart"      : boolean, 
        "callback"     : false | Callback,  
        "schedule"     : false | Schedule, 
        "requirements" : false | Requirements,  
        "trigger"      : false | Triggers,  
        "metadata:     : false | any object
    }

Parameters

Argument Required Type Description
activityId No int Activity ID. Either this, or "activityName" is required.
activityName No string Activity name. Either this, or "activityId" is required.
restart No boolean Restart Activity flag. Default is false.
callback No boolean or Callback Callback to use if Activity is restarted.
schedule No boolean or Schedule Schedule to use if Activity is restarted.
requirements No boolean or Requirements Prerequisites to use if Activity is restarted.
trigger No boolean or Trigger Trigger to use if Activity is restarted.
metadata No boolean or any object. Meta data.

Returns

Argument Type Description
returnValue boolean true (success) or false (failure).

Example

this.controller.serviceRequest("palm://com.palm.activitymanager/", {
   method: "complete",
   parameters: {
                 "activityId": 876
   },
   onSuccess: function(){ Mojo.Log.info("complete success"); },
   onFailure: function(){ Mojo.Log.info("complete failure"); }
});

 


create

Creates a new Activity and returns its ID.

You can create either a foreground or background Activity. A foreground Activity is run as soon as its specified prerequisites are met. After a background Activity's prerequisites are met, it is moved into a ready queue, and a limited number are allowed to run depending on system resources. Foreground is the default.

Activities can be scheduled to run at a specific time or when certain conditions are met or events occur.

Each of your created and owned Activities must have a unique name. To replace one of your existing Activities, set the "replace" flag to true. This cancels the original Activity and replaces it with the new Activity.

To keep an Activity alive and receive status updates, the parent (and adopters, if any) must set the "subscribe" flag to true. Otherwise, if the Activity is created with a callback and "subscribe=false", the Activity must be adopted immediately after the callback is invoked for the Activity to continue.

To indicate the Activity is fully-initialized and ready to launch, set the "start" flag to true. Activities with a callback should be started when created—the callback is invoked when the prerequisites have been met and, in the case of a background, non-immediate Activity, it has been cleared to run.

When requirements are not initially met

If the creator of the Activity also specifies "subscribe":true, and detailed events are enabled for that subscription, then the Activity Manager will generate either an immediate "start" event if the requirements are met, or an "update" event if the Activity is not yet ready to start due to missing requirements, schedule, or trigger. This allows the creating Service to determine if it should continue executing while waiting for the callback, or exit to free memory if it may be awhile before the Activity is ready to run.

Syntax

{
    "activity"       : Activity,
    "subscribe"      : boolean,
    "detailedEvents" : boolean,     
    "start"          : boolean,
    "replace"        : boolean
}

Parameters

Argument Required Type Description
activity Yes object Activity object.
subscribe No boolean Subscribe to Activity flag.
detailedEvents No boolean Flag to have the Activity Manager generate "update" events when the state of one of this Activity's requirements changes.
start No boolean Start Activity immediately flag.
replace No boolean Cancel Activity and replace with Activity of same name flag.

Returns

Argument Type Description
returnValue boolean true (success) or false (failure).
activityId int Activity ID.

Examples

In this section:

 

Create an Activity

Create an Activity with a given name and description.

   this.controller.serviceRequest("palm://com.palm.activitymanager/", {
      method: "create",
      parameters: {       
         "activity": {
                       "name": "basicactivity",
                       "description": "Test create",
                        "type": {
                                   "foreground": true
                                 }
                      },

                 "start": true,
                 "subscribe":true
          },
      onSuccess: function(e) { Mojo.Log.info("create success, activity="+JSON.stringify(e.activityId));},
      onFailure: function(e) { Mojo.Log.info("create failure, err="+JSON.stringify(e));}
   }); 

 

Create a Scheduled Activity

This creates an Activity that receives a "start" event on the subscription when the specified time is reached. The Activity is started as part of the create command.

   this.controller.serviceRequest("palm://com.palm.activitymanager/", {
      method: "create",
      parameters: {       
         "activity": {
            "name": "ScheduledActivity",
            "description": "Test create of scheduled activity",
            "type": {
                      "foreground": true
                    }
          },
          "schedule" : { "start" : "2010-05-27 13:22:00" },

          "start": true,
           "subscribe":true
      },
      onSuccess: function(e) { Mojo.Log.info("create Scheduled Activity success, activity="+JSON.stringify(e));},
      onFailure: function(e) { Mojo.Log.info("create Scheduled Activity failure, err="+JSON.stringify(e) );}
   });

 

Create a Triggered Activity

The following is an example of a basic Triggered Activity. The trigger is based on the connection status changing. An easy way to change the status is to switch into and out of airplane mode. After the initial success result, the second result causes the Trigger to fire.

  this.controller.serviceRequest("palm://com.palm.activitymanager/", {
     method: "create",
     parameters: {       
                   "activity": {
                                  "name": "triggeredActivity",
                                  "description": "Test create Activity with Trigger",
                                  "type": {
                                            "background": true
                                          },
                                 "trigger" : {
                                                "method" : "palm://com.palm.connectionmanager/getStatus", 
                                                "params" : {"subscribe":true}
                                             }
                               },
                   "start":     true,
                   "subscribe": true
                  },
     onSuccess: function(e) { Mojo.Log.info("Activity with Trigger success, return="+JSON.stringify(e));},
     onFailure: function(e) { Mojo.Log.info("Activity with Trigger failure");}
  }); 

 

Create an Activity with a Trigger and a Callback

The following example creates an Activity with a trigger and a callback. The trigger occurs when the device's connection status changes. When this occurs, the callback is invoked and the device's email service is launched to send an email.

  this.controller.serviceRequest("palm://com.palm.activitymanager/", {
  method: "create",
  parameters: {       
                "activity": {
                "name": "triggeredActivity",
                "description" : "Example triggered Activity",
                "type": {  "background": true },
                "trigger" : {
                               "method" : "palm://com.palm.connectionmanager/getStatus",  // Device status service
                               "params" : {"subscribe":true}
                            },
                "callback" : {
                                "method" : "palm://com.palm.applicationManager/open", // Launch email service via app manager service
                                "params" : { id: "com.palm.app.email",  // Send email
                                             params: {
                                                        summary: "test subject",
                                                        text: "Test email text.",
                                                        recipients: [{
                                                                       type: "email",
                                                                       role: 1,
                                                                       value:"Hal.Itosis@palm.com",
                                                                       contactDisplay: "Ginger Vitis" }]
                                                      }                                                                                                 
                                             }
                              }                                                                                           
              },
              "start"      : true  // Start immediately
            },
     onSuccess: function(e) { Mojo.Log.info("Activity with Trigger and Callback success, return="+JSON.stringify(e));},
     onFailure: function(e) { Mojo.Log.info("Activity with Trigger  and Callback failure");}
  }); 

 

Create an Activity with a Keyed Trigger Based on a db8 Watch

This example creates an activity with a keyed trigger and a callback. The trigger is based on a db8 watch method and query. If the results of the query change, the watch method invokes the callback function. The Activity Manager looks for the "fired" keyed property in the results that are returned. The query contains two where clauses indicating a specific account and a revision (_rev) field. The revision is a counter that is incremented every time a db8 JSON object changes and is stored with the object.

See the db8 documentation for more information on formatting queries.

  this.controller.serviceRequest("palm://com.palm.activitymanager/", {
     method: "create",
     parameters: {       
                   "activity": { 
                               "callback": { "method": "palm://com.palm.myservice/userEdit" }, 
                               "description": "my db watch", 
                                "name": "My DbWatch", 
                                "trigger": { 
                                             "key": "fired", 
                                             "method": "palm://com.palm.db/watch", 
                                             "params": { 
                                                         "query": { 
                                                                    "from": "com.palm.contact:1", 
                                                                    "where": [ 
                                                                                { "prop": "accountId", "op": "=", "val": "21e2" }, 
                                                                                { "prop": "_rev", "op": ">", "val": 11410 } 
                                                                              ], 
                                                                     "incDel": true 
                                                                   } 
                                                       } 
                                             }, 
                                "type": { "background": true, "persist": true }, 
                                "requirements": { "idle": 30 }                                                          
                             },
                  "start": true 
     }, 
     onSuccess: function(e) { Mojo.Log.info("Create Activity with db8 watch success, return="+JSON.stringify(e));},
     onFailure: function(e) { Mojo.Log.info("Create Activity with db8 watch failure, err="+JSON.stringify(e));}
  }); 

 


getDetails

Requests an Activity's full details, including associations.

Syntax

{
  "activityId"  : int |  "activityName" : string
}

Parameters

Argument Required Type Description
activityId No int Activity ID. Either this or activityName must be specified.
activityName No string Activity name. Either this or activityId must be specified.

Returns

Argument Type Description
returnValue boolean true (success) or false (failure)
activity Activity Activity object including associations.

Example

this.controller.serviceRequest("palm://com.palm.activitymanager/", {
   method: "getDetails",
   parameters: {
                 "activityId": 3
   },
   onSuccess: function(e) { Mojo.Log.info("getDetails success, activity="+JSON.stringify(e.activity));},
   onFailure: function(e) { Mojo.Log.info("getActivity failure");}
});

 


monitor

Given an activity ID, returns the current activity state. If the caller chooses to subscribe, additional Activity status updates are returned as they occur.

Syntax

{
  "activityId"     : int |  "activityName"   : string,
  "subscribe"      : boolean,
  "detailedEvents" : boolean
}

Parameters

Argument Required Type Description
activityId No int Activity ID. Either this, or "activityName" is required.
activityName No string Activity name. Either this, or "activityId" is required.
subscribe Yes boolean Activity subscription flag.
detailedEvents Yes boolean Flag to have the Activity Manager generate "update" events when the state of one of this Activity's requirements changes.

Returns

Argument Type Description
returnValue boolean true (success) or false (failure).
state string Activity state.

Example

this.controller.serviceRequest("palm://com.palm.activitymanager/", {
   method: "monitor",
   parameters: {
                 "activityId": 3,
                 "subscribe" : false,
                 "detailedEvents" : false
    },
    onSuccess: function(e) { Mojo.Log.info("Monitor success, state="+JSON.stringify(e.state));},
    onFailure: function(e) { Mojo.Log.info("Monitor failure");}
});

 


release

Allows a parent to free an Activity and notify other subscribers. The Activity is cancelled unless one of its non-parent subscribers adopts it and becomes the new parent. This has to happen in the timeout specified. If no timeout is specified, the Activity is cancelled immediately. For a completely safe transfer, a subscribing app or service, prior to the release, should already have called adopt, indicating its willingness to take over as the parent.

Syntax

{
  "activityId"  : int | "activityName" : string,
  "timeout"     : int
}

Parameters

Argument Required Type Description
activityId No int Activity ID. Either this or "activityName" is required.
activityName No string Activity name. Either this or "activityId" is required.
timeout No int Time to wait, in seconds, for Activity to be adopted after release.

Returns

Argument Type Description
returnValue boolean true (success) or false (failure)

Example

this.controller.serviceRequest("palm://com.palm.activitymanager/", {
   method: "release",
   parameters: {
                 "activityId" : 876,
                 "timeout"    : 30 
   },
   onSuccess: function(){ Mojo.Log.info("release success"); },
   onFailure: function(){ Mojo.Log.info("release failure"); }
});

 


start

Attempts to start the specified Activity, either moving it from the "init" state to be eligible to run, or resuming it if it is currently paused. This sends "start" events to any subscribed listeners once the Activity is cleared to begin. If the "force" parameter is present (and true), other Activities could be cancelled to free resources the Activity needs to run.

Syntax

{
  "activityId"  : int | "activityName" : string,
  "force"       : boolean
}

Parameters

Argument Required Type Description
activityId No int Activity ID. Either this or "activityName" is required.
activityName No string Activity name. Either this or "activityId" is required.
force No boolean Force the Activity run flag. If "true", other Activities could be cancelled to free resources the Activity needs to run.

Returns

Argument Type Description
returnValue boolean true (success) or false (failure).

Example

 


stop

Stops an Activity and sends a "stop" event to all Activity subscribers. This succeeds unless the Activity is already cancelled.

This is different from the cancel method in that more time is allowed for the Activity to clean up. For example, this might matter for an email sync service that needs more time to finish downloading a large email attachment. On a "cancel", it should immediately abort the download, clean up, and exit. On a "stop," it should finish downloading the attachment in some reasonable amount of time, say, 10-15 seconds.

Syntax

{
  "activityId"  : int | "activityName" : string
}

Parameters

Argument Required Type Description
activityId No int Activity ID. Either this or "activityName" is required.
activityName No string Activity name. Either this or "activityId" is required.

Returns

Argument Type Description
returnValue boolean true (success) or false (failure).

Example

this.controller.serviceRequest("palm://com.palm.activitymanager/", {
   method: "stop",
   parameters: {
                 "activityId": 876
   },
   onSuccess: function(e){ Mojo.Log.info("stop success"); },
   onFailure: function(e){ Mojo.Log.info("stop failure"); }
});

 


Activity Lifecycle

In most cases, an Activity is created to run in either the foreground or the background. A foreground Activity runs as soon as its specified prerequisites (schedule, requirements, triggers) are met. When its prerequisites are met, a background Activity is moved into a ready queue, and a limited number are allowed to run depending on system resources. Activities can be scheduled to run at a specific time or when certain conditions are met or events occur. They can also be scheduled to repeat at a particular interval. The Activity Manager attempts to batch-run Activities repeating at the same interval allowing the device to suspend/restart less frequently, conserving battery use.

When an Activity finishes, the parent informs the Activity Manager with the complete method. If the Activity has other subscribers, they are sent "complete" events. An Activity is not considered finished until all of its subscribers exit. An Activity marked explicit (via the Type object) can only be terminated by its parent with a stop, cancel, or complete call. Otherwise, after a timeout, it is restarted via a specified callback. Explicit termination is also required if the Activity is defined with the persist attribute (Type object). In this case, the Activity state is stored in db8, continues across reboots and requires explicit termination.

Activities that need to run to completion should be marked "explicit" or "persist".

There are four methods specifically for ending an Activity:

  1. cancel—The Activity is ended immediately, with little or no time for clean-up.

  2. complete—The Activity is ended, with an option to restart with new attributes.

  3. stop—The Activity is ended, but some time is allowed for clean-up.

  4. release—The parent frees an Activity, allowing time for adopters to take over as the parent and let the Activity continue. If no adopter takes over, the Activity is ended.

 

Handling Incoming Service Requests

Any entity with bus access can generate a service request. Mostly they come from apps or the Activity Manager itself as a result of a scheduled or triggered Activity.

If the call comes from an app, the Mojo Framework should have allocated an Activity for the app (or the specific card) and passed it along with the other service call arguments. If the incoming call is the callback generated for a scheduled Activity that has been selected to run, the Activity Manager adds the "$activity" property to the other callback parameters. This property contains information about the Activity such as its requirements, triggers, and metadata.

Before processing a request, a service should associate itself with the Activity via the adopt or monitor calls. If the request could have a life of its own (a sync, for example), then calling adopt makes sense since the service could take over as the Activity's parent if the current parent exits. Otherwise, your service should call monitor.

A service should wait until the adopt or monitor call returns successfully before beginning Activity work. If either of these calls fail, it indicates the caller has exited and the request should not be processed.

Once adopt or monitor succeeds, the service can proceed to do the work indicated in the original incoming request. If the request was to simply kick-off a long running task, then the service should do this and simply return.

A service should continue to process incoming events on an Activity subscription. If a service receives a "cancel" event and the service did not use adopt to inform the Activity Manager it was willing to take over as the Activity parent, it should be prepared to stop Activity work and unsubscribe. If it did use adopt and it receives the "orphan" event (indicating that the original parent(s) have unsubscribed and the service is now the Activity parent), then, when it is done, the service should call complete to inform the Activity Manager before unsubscribing.

 

Activity Lifecycle Flowchart

 

Example Lifecycle Flows

Normal inbound app request

  • App calls service method.
  • Service subscribes to Activity by calling adopt (or monitor) using the app-provided Activity ID.
  • Activity Manager returns success result to service.
  • Service performs requested work.
  • Service unsubscribes from Activity.
  • Service returns result to app.

Potentially long running inbound app request

  • App calls service method.
  • Service subscribes to Activity by calling adopt (or monitor) using the app-provided Activity ID.
  • Activity Manager returns success result to service.
  • Service returns success result to app.
  • Service performs requested work.
  • Service unsubscribes from Activity.

Incoming scheduled background activity

  • Activity Manager calls service-specified callback method.
  • Service subscribes to Activity by calling adopt (or monitor) using the app-provided Activity ID.
  • Activity Manager returns success result to service.
  • Service performs requested work.
  • Service calls complete for Activity.
  • Activity Manager returns success.
  • Service unsubscribes from Activity.

 


Activity Checklists

Incoming Requests

  • Does your Service adopt (or join) the Activities on incoming requests? If not, your Service is not properly prioritized, and could be killed if the Activity Manager thinks it is running without any Activities.
  • Does your Service wait for the adopt (or join) to succeed before proceeding to perform the request?
  • For a long running request, does your service watch for "cancel" events and stop processing the Activity if one is received?
  • For background and non-immediate Activities, does your service process a bite-sized chunk of work and then re-schedule the Activity if there is more work to do rather than leave the background Activity in the running state for a long period of time?
  • Did you remember to complete your persistent or explicit Activities? Otherwise, your callback continues to be invoked.

Scheduled Activities

  • Does your Service exit when it has no work, and use the Activity Manager to schedule an Activity to launch it when more work becomes available?
  • Does your Service check to make sure its Trigger calls did not produce errors? For example, if bad parameters are provided for the Trigger, it will repeatedly fire, placing your Service and the Activity Manager in a infinite loop.
  • Does you Service use complete to update an Activity with new db8 watch parameters, rather than calling complete followed by create to start a new Activity? A crash between those two calls could leave you with no Activity.

Scheduled Interval Activities

  • Does your Service use a smart interval for any repeating Activities, rather than creating a new scheduled Activity after the last completes?
  • Does your Service not use a "precise" interval if it does not need one? Precise intervals are not synchronized with other interval-based Activities and consume more power.
  • Does your Service call complete with "restart":true specified to reschedule the Activity?