Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 08992ac5 authored by Christopher Tate's avatar Christopher Tate Committed by Chris Tate
Browse files

API refactor: context.startForegroundService()

Rather than require an a-priori Notification be supplied in order to
start a service directly into the foreground state, we adopt a two-stage
compound operation for undertaking ongoing service work even from a
background execution state.  Context#startForegroundService() is not
subject to background restrictions, with the requirement that the
service formally enter the foreground state via startForeground() within
5 seconds.  If the service does not do so, it is stopped by the OS and
the app is blamed with a service ANR.

We also introduce a new flavor of PendingIntent that starts a service
into this two-stage "promises to call startForeground()" sequence, so
that deferred and second-party launches can take advantage of it.

Bug 36130212
Test: CTS

Change-Id: I96d6b23fcfc27d8fa606827b7d48a093611b2345
(cherry picked from commit 79047c62)
parent 217ecd07
Loading
Loading
Loading
Loading
+5 −1
Original line number Diff line number Diff line
@@ -5586,7 +5586,7 @@ package android.app {
    method public boolean removeAutomaticZenRule(java.lang.String);
    method public final void setInterruptionFilter(int);
    method public void setNotificationPolicy(android.app.NotificationManager.Policy);
    method public android.content.ComponentName startServiceInForeground(android.content.Intent, int, android.app.Notification);
    method public deprecated android.content.ComponentName startServiceInForeground(android.content.Intent, int, android.app.Notification);
    method public boolean updateAutomaticZenRule(java.lang.String, android.app.AutomaticZenRule);
    field public static final java.lang.String ACTION_INTERRUPTION_FILTER_CHANGED = "android.app.action.INTERRUPTION_FILTER_CHANGED";
    field public static final java.lang.String ACTION_NOTIFICATION_POLICY_ACCESS_GRANTED_CHANGED = "android.app.action.NOTIFICATION_POLICY_ACCESS_GRANTED_CHANGED";
@@ -5641,6 +5641,7 @@ package android.app {
    method public java.lang.String getCreatorPackage();
    method public int getCreatorUid();
    method public android.os.UserHandle getCreatorUserHandle();
    method public static android.app.PendingIntent getForegroundService(android.content.Context, int, android.content.Intent, int);
    method public android.content.IntentSender getIntentSender();
    method public static android.app.PendingIntent getService(android.content.Context, int, android.content.Intent, int);
    method public deprecated java.lang.String getTargetPackage();
@@ -8858,6 +8859,7 @@ package android.content {
    method public abstract void startActivities(android.content.Intent[], android.os.Bundle);
    method public abstract void startActivity(android.content.Intent);
    method public abstract void startActivity(android.content.Intent, android.os.Bundle);
    method public abstract android.content.ComponentName startForegroundService(android.content.Intent);
    method public abstract boolean startInstrumentation(android.content.ComponentName, java.lang.String, android.os.Bundle);
    method public abstract void startIntentSender(android.content.IntentSender, android.content.Intent, int, int, int) throws android.content.IntentSender.SendIntentException;
    method public abstract void startIntentSender(android.content.IntentSender, android.content.Intent, int, int, int, android.os.Bundle) throws android.content.IntentSender.SendIntentException;
@@ -9049,6 +9051,7 @@ package android.content {
    method public void startActivities(android.content.Intent[], android.os.Bundle);
    method public void startActivity(android.content.Intent);
    method public void startActivity(android.content.Intent, android.os.Bundle);
    method public android.content.ComponentName startForegroundService(android.content.Intent);
    method public boolean startInstrumentation(android.content.ComponentName, java.lang.String, android.os.Bundle);
    method public void startIntentSender(android.content.IntentSender, android.content.Intent, int, int, int) throws android.content.IntentSender.SendIntentException;
    method public void startIntentSender(android.content.IntentSender, android.content.Intent, int, int, int, android.os.Bundle) throws android.content.IntentSender.SendIntentException;
@@ -40679,6 +40682,7 @@ package android.test.mock {
    method public void startActivities(android.content.Intent[], android.os.Bundle);
    method public void startActivity(android.content.Intent);
    method public void startActivity(android.content.Intent, android.os.Bundle);
    method public android.content.ComponentName startForegroundService(android.content.Intent);
    method public boolean startInstrumentation(android.content.ComponentName, java.lang.String, android.os.Bundle);
    method public void startIntentSender(android.content.IntentSender, android.content.Intent, int, int, int) throws android.content.IntentSender.SendIntentException;
    method public void startIntentSender(android.content.IntentSender, android.content.Intent, int, int, int, android.os.Bundle) throws android.content.IntentSender.SendIntentException;
+5 −1
Original line number Diff line number Diff line
@@ -5780,7 +5780,7 @@ package android.app {
    method public boolean removeAutomaticZenRule(java.lang.String);
    method public final void setInterruptionFilter(int);
    method public void setNotificationPolicy(android.app.NotificationManager.Policy);
    method public android.content.ComponentName startServiceInForeground(android.content.Intent, int, android.app.Notification);
    method public deprecated android.content.ComponentName startServiceInForeground(android.content.Intent, int, android.app.Notification);
    method public boolean updateAutomaticZenRule(java.lang.String, android.app.AutomaticZenRule);
    field public static final java.lang.String ACTION_INTERRUPTION_FILTER_CHANGED = "android.app.action.INTERRUPTION_FILTER_CHANGED";
    field public static final java.lang.String ACTION_NOTIFICATION_POLICY_ACCESS_GRANTED_CHANGED = "android.app.action.NOTIFICATION_POLICY_ACCESS_GRANTED_CHANGED";
@@ -5835,6 +5835,7 @@ package android.app {
    method public java.lang.String getCreatorPackage();
    method public int getCreatorUid();
    method public android.os.UserHandle getCreatorUserHandle();
    method public static android.app.PendingIntent getForegroundService(android.content.Context, int, android.content.Intent, int);
    method public android.content.IntentSender getIntentSender();
    method public static android.app.PendingIntent getService(android.content.Context, int, android.content.Intent, int);
    method public deprecated java.lang.String getTargetPackage();
@@ -9353,6 +9354,7 @@ package android.content {
    method public abstract void startActivities(android.content.Intent[], android.os.Bundle);
    method public abstract void startActivity(android.content.Intent);
    method public abstract void startActivity(android.content.Intent, android.os.Bundle);
    method public abstract android.content.ComponentName startForegroundService(android.content.Intent);
    method public abstract boolean startInstrumentation(android.content.ComponentName, java.lang.String, android.os.Bundle);
    method public abstract void startIntentSender(android.content.IntentSender, android.content.Intent, int, int, int) throws android.content.IntentSender.SendIntentException;
    method public abstract void startIntentSender(android.content.IntentSender, android.content.Intent, int, int, int, android.os.Bundle) throws android.content.IntentSender.SendIntentException;
@@ -9558,6 +9560,7 @@ package android.content {
    method public void startActivities(android.content.Intent[], android.os.Bundle);
    method public void startActivity(android.content.Intent);
    method public void startActivity(android.content.Intent, android.os.Bundle);
    method public android.content.ComponentName startForegroundService(android.content.Intent);
    method public boolean startInstrumentation(android.content.ComponentName, java.lang.String, android.os.Bundle);
    method public void startIntentSender(android.content.IntentSender, android.content.Intent, int, int, int) throws android.content.IntentSender.SendIntentException;
    method public void startIntentSender(android.content.IntentSender, android.content.Intent, int, int, int, android.os.Bundle) throws android.content.IntentSender.SendIntentException;
@@ -44117,6 +44120,7 @@ package android.test.mock {
    method public void startActivities(android.content.Intent[], android.os.Bundle);
    method public void startActivity(android.content.Intent);
    method public void startActivity(android.content.Intent, android.os.Bundle);
    method public android.content.ComponentName startForegroundService(android.content.Intent);
    method public boolean startInstrumentation(android.content.ComponentName, java.lang.String, android.os.Bundle);
    method public void startIntentSender(android.content.IntentSender, android.content.Intent, int, int, int) throws android.content.IntentSender.SendIntentException;
    method public void startIntentSender(android.content.IntentSender, android.content.Intent, int, int, int, android.os.Bundle) throws android.content.IntentSender.SendIntentException;
+5 −1
Original line number Diff line number Diff line
@@ -5599,7 +5599,7 @@ package android.app {
    method public boolean removeAutomaticZenRule(java.lang.String);
    method public final void setInterruptionFilter(int);
    method public void setNotificationPolicy(android.app.NotificationManager.Policy);
    method public android.content.ComponentName startServiceInForeground(android.content.Intent, int, android.app.Notification);
    method public deprecated android.content.ComponentName startServiceInForeground(android.content.Intent, int, android.app.Notification);
    method public boolean updateAutomaticZenRule(java.lang.String, android.app.AutomaticZenRule);
    field public static final java.lang.String ACTION_INTERRUPTION_FILTER_CHANGED = "android.app.action.INTERRUPTION_FILTER_CHANGED";
    field public static final java.lang.String ACTION_NOTIFICATION_POLICY_ACCESS_GRANTED_CHANGED = "android.app.action.NOTIFICATION_POLICY_ACCESS_GRANTED_CHANGED";
@@ -5654,6 +5654,7 @@ package android.app {
    method public java.lang.String getCreatorPackage();
    method public int getCreatorUid();
    method public android.os.UserHandle getCreatorUserHandle();
    method public static android.app.PendingIntent getForegroundService(android.content.Context, int, android.content.Intent, int);
    method public android.content.IntentSender getIntentSender();
    method public static android.app.PendingIntent getService(android.content.Context, int, android.content.Intent, int);
    method public deprecated java.lang.String getTargetPackage();
@@ -8890,6 +8891,7 @@ package android.content {
    method public abstract void startActivities(android.content.Intent[], android.os.Bundle);
    method public abstract void startActivity(android.content.Intent);
    method public abstract void startActivity(android.content.Intent, android.os.Bundle);
    method public abstract android.content.ComponentName startForegroundService(android.content.Intent);
    method public abstract boolean startInstrumentation(android.content.ComponentName, java.lang.String, android.os.Bundle);
    method public abstract void startIntentSender(android.content.IntentSender, android.content.Intent, int, int, int) throws android.content.IntentSender.SendIntentException;
    method public abstract void startIntentSender(android.content.IntentSender, android.content.Intent, int, int, int, android.os.Bundle) throws android.content.IntentSender.SendIntentException;
@@ -9082,6 +9084,7 @@ package android.content {
    method public void startActivities(android.content.Intent[], android.os.Bundle);
    method public void startActivity(android.content.Intent);
    method public void startActivity(android.content.Intent, android.os.Bundle);
    method public android.content.ComponentName startForegroundService(android.content.Intent);
    method public boolean startInstrumentation(android.content.ComponentName, java.lang.String, android.os.Bundle);
    method public void startIntentSender(android.content.IntentSender, android.content.Intent, int, int, int) throws android.content.IntentSender.SendIntentException;
    method public void startIntentSender(android.content.IntentSender, android.content.Intent, int, int, int, android.os.Bundle) throws android.content.IntentSender.SendIntentException;
@@ -40883,6 +40886,7 @@ package android.test.mock {
    method public void startActivities(android.content.Intent[], android.os.Bundle);
    method public void startActivity(android.content.Intent);
    method public void startActivity(android.content.Intent, android.os.Bundle);
    method public android.content.ComponentName startForegroundService(android.content.Intent);
    method public boolean startInstrumentation(android.content.ComponentName, java.lang.String, android.os.Bundle);
    method public void startIntentSender(android.content.IntentSender, android.content.Intent, int, int, int) throws android.content.IntentSender.SendIntentException;
    method public void startIntentSender(android.content.IntentSender, android.content.Intent, int, int, int, android.os.Bundle) throws android.content.IntentSender.SendIntentException;
+7 −0
Original line number Diff line number Diff line
@@ -405,6 +405,13 @@ public class ActivityManager {
     */
    public static final int INTENT_SENDER_SERVICE = 4;

    /**
     * Type for IActivityManaqer.getIntentSender: this PendingIntent is
     * for a startForegroundService operation.
     * @hide
     */
    public static final int INTENT_SENDER_FOREGROUND_SERVICE = 5;

    /** @hide User operation call: success! */
    public static final int USER_OP_SUCCESS = 0;

+20 −7
Original line number Diff line number Diff line
@@ -1447,14 +1447,21 @@ class ContextImpl extends Context {
    @Override
    public ComponentName startService(Intent service) {
        warnIfCallingFromSystemProcess();
        return startServiceCommon(service, -1, null, mUser);
        return startServiceCommon(service, -1, null, false, mUser);
    }

    @Override
    public ComponentName startForegroundService(Intent service) {
        warnIfCallingFromSystemProcess();
        return startServiceCommon(service, -1, null, true, mUser);
    }

    // STOPSHIP: remove when NotificationManager.startServiceInForeground() is retired
    @Override
    public ComponentName startServiceInForeground(Intent service,
            int id, Notification notification) {
        warnIfCallingFromSystemProcess();
        return startServiceCommon(service, id, notification, mUser);
        return startServiceCommon(service, id, notification, false, mUser);
    }

    @Override
@@ -1465,24 +1472,30 @@ class ContextImpl extends Context {

    @Override
    public ComponentName startServiceAsUser(Intent service, UserHandle user) {
        return startServiceCommon(service, -1, null, user);
        return startServiceCommon(service, -1, null, false, user);
    }

    @Override
    public ComponentName startForegroundServiceAsUser(Intent service, UserHandle user) {
        return startServiceCommon(service, -1, null, true, user);
    }

    // STOPSHIP: remove when NotificationManager.startServiceInForeground() is retired
    @Override
    public ComponentName startServiceInForegroundAsUser(Intent service,
            int id, Notification notification, UserHandle user) {
        return startServiceCommon(service, id, notification, user);
        return startServiceCommon(service, id, notification, false, user);
    }

    private ComponentName startServiceCommon(Intent service, int id, Notification notification,
            UserHandle user) {
            boolean requireForeground, UserHandle user) {
        try {
            validateServiceIntent(service);
            service.prepareToLeaveProcess(this);
            ComponentName cn = ActivityManager.getService().startService(
                mMainThread.getApplicationThread(), service, service.resolveTypeIfNeeded(
                            getContentResolver()), id, notification, getOpPackageName(),
                            user.getIdentifier());
                            getContentResolver()), id, notification, requireForeground,
                            getOpPackageName(), user.getIdentifier());
            if (cn != null) {
                if (cn.getPackageName().equals("!")) {
                    throw new SecurityException(
Loading