Merge "Work on issue #36891897: Need to ensure foreground services can't..." into oc-dev
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index 2230472..6bc59fc 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -458,42 +458,45 @@
     /** @hide Process is important to the user, but not something they are aware of. */
     public static final int PROCESS_STATE_IMPORTANT_BACKGROUND = 7;
 
+    /** @hide Process is in the background transient so we will try to keep running. */
+    public static final int PROCESS_STATE_TRANSIENT_BACKGROUND = 8;
+
     /** @hide Process is in the background running a backup/restore operation. */
-    public static final int PROCESS_STATE_BACKUP = 8;
+    public static final int PROCESS_STATE_BACKUP = 9;
 
     /** @hide Process is in the background, but it can't restore its state so we want
      * to try to avoid killing it. */
-    public static final int PROCESS_STATE_HEAVY_WEIGHT = 9;
+    public static final int PROCESS_STATE_HEAVY_WEIGHT = 10;
 
     /** @hide Process is in the background running a service.  Unlike oom_adj, this level
      * is used for both the normal running in background state and the executing
      * operations state. */
-    public static final int PROCESS_STATE_SERVICE = 10;
+    public static final int PROCESS_STATE_SERVICE = 11;
 
     /** @hide Process is in the background running a receiver.   Note that from the
      * perspective of oom_adj receivers run at a higher foreground level, but for our
      * prioritization here that is not necessary and putting them below services means
      * many fewer changes in some process states as they receive broadcasts. */
-    public static final int PROCESS_STATE_RECEIVER = 11;
+    public static final int PROCESS_STATE_RECEIVER = 12;
 
     /** @hide Process is in the background but hosts the home activity. */
-    public static final int PROCESS_STATE_HOME = 12;
+    public static final int PROCESS_STATE_HOME = 13;
 
     /** @hide Process is in the background but hosts the last shown activity. */
-    public static final int PROCESS_STATE_LAST_ACTIVITY = 13;
+    public static final int PROCESS_STATE_LAST_ACTIVITY = 14;
 
     /** @hide Process is being cached for later use and contains activities. */
-    public static final int PROCESS_STATE_CACHED_ACTIVITY = 14;
+    public static final int PROCESS_STATE_CACHED_ACTIVITY = 15;
 
     /** @hide Process is being cached for later use and is a client of another cached
      * process that contains activities. */
-    public static final int PROCESS_STATE_CACHED_ACTIVITY_CLIENT = 15;
+    public static final int PROCESS_STATE_CACHED_ACTIVITY_CLIENT = 16;
 
     /** @hide Process is being cached for later use and is empty. */
-    public static final int PROCESS_STATE_CACHED_EMPTY = 16;
+    public static final int PROCESS_STATE_CACHED_EMPTY = 17;
 
     /** @hide Process does not exist. */
-    public static final int PROCESS_STATE_NONEXISTENT = 17;
+    public static final int PROCESS_STATE_NONEXISTENT = 18;
 
     /** @hide The lowest process state number */
     public static final int MIN_PROCESS_STATE = PROCESS_STATE_PERSISTENT;
@@ -503,7 +506,7 @@
 
     /** @hide Should this process state be considered a background state? */
     public static final boolean isProcStateBackground(int procState) {
-        return procState >= PROCESS_STATE_BACKUP;
+        return procState >= PROCESS_STATE_TRANSIENT_BACKGROUND;
     }
 
     /** @hide requestType for assist context: only basic information. */
@@ -3233,7 +3236,7 @@
                 return IMPORTANCE_SERVICE;
             } else if (procState > PROCESS_STATE_HEAVY_WEIGHT) {
                 return IMPORTANCE_CANT_SAVE_STATE;
-            } else if (procState >= PROCESS_STATE_IMPORTANT_BACKGROUND) {
+            } else if (procState >= PROCESS_STATE_TRANSIENT_BACKGROUND) {
                 return IMPORTANCE_PERCEPTIBLE;
             } else if (procState >= PROCESS_STATE_IMPORTANT_FOREGROUND) {
                 return IMPORTANCE_VISIBLE;
@@ -3290,7 +3293,7 @@
             } else if (importance > IMPORTANCE_CANT_SAVE_STATE) {
                 return PROCESS_STATE_HEAVY_WEIGHT;
             } else if (importance >= IMPORTANCE_PERCEPTIBLE) {
-                return PROCESS_STATE_IMPORTANT_BACKGROUND;
+                return PROCESS_STATE_TRANSIENT_BACKGROUND;
             } else if (importance >= IMPORTANCE_VISIBLE) {
                 return PROCESS_STATE_IMPORTANT_FOREGROUND;
             } else if (importance >= IMPORTANCE_TOP_SLEEPING) {
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 2e2d444..bf7af20 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -323,6 +323,12 @@
     public static final int BIND_ADJUST_WITH_ACTIVITY = 0x0080;
 
     /**
+     * @hide Flag for {@link #bindService}: like {@link #BIND_NOT_FOREGROUND}, but puts it
+     * up in to the important background state (instead of transient).
+     */
+    public static final int BIND_IMPORTANT_BACKGROUND = 0x00800000;
+
+    /**
      * @hide Flag for {@link #bindService}: allows application hosting service to manage whitelists
      * such as temporary allowing a {@code PendingIntent} to bypass Power Save mode.
      */
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 95be39b..f215ae7 100755
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -724,6 +724,19 @@
             "android.settings.APPLICATION_DETAILS_SETTINGS";
 
     /**
+     * Activity Action: Show list of applications that have been running
+     * foreground services (to the user "running in the background").
+     * <p>
+     * Input: Extras "packages" is a string array of package names.
+     * <p>
+     * Output: Nothing.
+     * @hide
+     */
+    @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+    public static final String ACTION_FOREGROUND_SERVICES_SETTINGS =
+            "android.settings.FOREGROUND_SERVICES_SETTINGS";
+
+    /**
      * Activity Action: Show screen for controlling which apps can ignore battery optimizations.
      * <p>
      * Input: Nothing.
@@ -8980,13 +8993,30 @@
          * Activity manager specific settings.
          * This is encoded as a key=value list, separated by commas. Ex:
          *
-         * "enforce_bg_check=true,max_cached_processes=24"
+         * "gc_timeout=5000,max_cached_processes=24"
          *
          * The following keys are supported:
          *
          * <pre>
-         * enforce_bg_check                     (boolean)
          * max_cached_processes                 (int)
+         * background_settle_time               (long)
+         * foreground_service_ui_min_time       (long)
+         * content_provider_retain_time         (long)
+         * gc_timeout                           (long)
+         * gc_min_interval                      (long)
+         * full_pss_min_interval                (long)
+         * full_pss_lowered_interval            (long)
+         * power_check_delay                    (long)
+         * wake_lock_min_check_duration         (long)
+         * cpu_min_check_duration               (long)
+         * service_usage_interaction_time       (long)
+         * usage_stats_interaction_interval     (long)
+         * service_restart_duration             (long)
+         * service_reset_run_duration           (long)
+         * service_restart_duration_factor      (int)
+         * service_min_restart_time_between     (long)
+         * service_max_inactivity               (long)
+         * service_bg_start_timeout             (long)
          * </pre>
          *
          * <p>
diff --git a/core/java/com/android/internal/app/procstats/ProcessState.java b/core/java/com/android/internal/app/procstats/ProcessState.java
index 8c2c236..9470668 100644
--- a/core/java/com/android/internal/app/procstats/ProcessState.java
+++ b/core/java/com/android/internal/app/procstats/ProcessState.java
@@ -86,6 +86,7 @@
         STATE_TOP,                      // ActivityManager.PROCESS_STATE_TOP_SLEEPING
         STATE_IMPORTANT_FOREGROUND,     // ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND
         STATE_IMPORTANT_BACKGROUND,     // ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND
+        STATE_IMPORTANT_BACKGROUND,     // ActivityManager.PROCESS_STATE_TRANSIENT_BACKGROUND
         STATE_BACKUP,                   // ActivityManager.PROCESS_STATE_BACKUP
         STATE_HEAVY_WEIGHT,             // ActivityManager.PROCESS_STATE_HEAVY_WEIGHT
         STATE_SERVICE,                  // ActivityManager.PROCESS_STATE_SERVICE
diff --git a/core/java/com/android/internal/notification/SystemNotificationChannels.java b/core/java/com/android/internal/notification/SystemNotificationChannels.java
index ef20750..fef85da 100644
--- a/core/java/com/android/internal/notification/SystemNotificationChannels.java
+++ b/core/java/com/android/internal/notification/SystemNotificationChannels.java
@@ -45,6 +45,7 @@
     public static String ALERTS = "ALERTS";
     public static String RETAIL_MODE = "RETAIL_MODE";
     public static String USB = "USB";
+    public static String FOREGROUND_SERVICE = "FOREGROUND_SERVICE";
 
     public static void createAll(Context context) {
         final NotificationManager nm = context.getSystemService(NotificationManager.class);
@@ -125,6 +126,11 @@
                 context.getString(R.string.notification_channel_usb),
                 NotificationManager.IMPORTANCE_MIN));
 
+        channelsList.add(new NotificationChannel(
+                FOREGROUND_SERVICE,
+                context.getString(R.string.notification_channel_foreground_service),
+                NotificationManager.IMPORTANCE_MIN));
+
         nm.createNotificationChannels(channelsList);
     }
 
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 35b12ff..e633d66 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -644,6 +644,29 @@
     <!-- Text shown when viewing channel settings for notifications related to a usb connection -->
     <string name="notification_channel_usb">USB connection</string>
 
+    <!-- Text shown when viewing channel settings for notifications related to running foreground
+        services [CHAR LIMIT=NONE] -->
+    <string name="notification_channel_foreground_service">Apps running in background</string>
+
+    <!-- Label for foreground service notification when one app is running. [CHAR LIMIT=NONE] -->
+    <string name="foreground_service_app_in_background"><xliff:g id="app_name">%1$s</xliff:g> is
+        running in the background</string>
+
+    <!-- Label for foreground service notification when multiple apps are running.
+        [CHAR LIMIT=NONE] -->
+    <string name="foreground_service_apps_in_background"><xliff:g id="number">%1$d</xliff:g> apps
+        are running in the background</string>
+
+    <!-- Content for foreground service notification when one app is running.
+        [CHAR LIMIT=NONE] -->
+    <string name="foreground_service_tap_for_details">Tap for details on battery and
+        data usage</string>
+
+    <!-- Separator for foreground service notification content listing all apps when there
+        are multiple apps running [CHAR LIMIT=NONE] -->
+    <string name="foreground_service_multiple_separator"><xliff:g id="left_side">%1$s</xliff:g>,
+        <xliff:g id="right_side">%2$s</xliff:g></string>
+
     <!-- Displayed to the user to tell them that they have started up the phone in "safe mode" -->
     <string name="safeMode">Safe mode</string>
 
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 1e529da7..5c17788 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -2969,6 +2969,12 @@
   <java-symbol type="string" name="notification_channel_usb" />
   <java-symbol type="string" name="config_defaultAutofillService" />
 
+  <java-symbol type="string" name="notification_channel_foreground_service" />
+  <java-symbol type="string" name="foreground_service_app_in_background" />
+  <java-symbol type="string" name="foreground_service_apps_in_background" />
+  <java-symbol type="string" name="foreground_service_tap_for_details" />
+  <java-symbol type="string" name="foreground_service_multiple_separator" />
+
   <!-- ETWS primary messages -->
   <java-symbol type="string" name="etws_primary_default_message_earthquake" />
 
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index bf39bc4..490bee4 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -539,6 +539,17 @@
             </intent-filter>
         </activity>
 
+        <activity android:name=".ForegroundServicesDialog"
+            android:process=":fgservices"
+            android:excludeFromRecents="true"
+            android:launchMode="singleTop"
+            android:theme="@*android:style/Theme.DeviceDefault.Settings.Dialog">
+            <intent-filter android:priority="1">
+                <action android:name="android.settings.FOREGROUND_SERVICES_SETTINGS" />
+                <category android:name="android.intent.category.DEFAULT" />
+            </intent-filter>
+        </activity>
+
         <!-- Doze with notifications, run in main sysui process for every user  -->
         <service
             android:name=".doze.DozeService"
diff --git a/packages/SystemUI/res/layout/foreground_service_item.xml b/packages/SystemUI/res/layout/foreground_service_item.xml
new file mode 100644
index 0000000..0a1dea0
--- /dev/null
+++ b/packages/SystemUI/res/layout/foreground_service_item.xml
@@ -0,0 +1,48 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2017, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:minHeight="?android:attr/listPreferredItemHeight"
+    android:paddingStart="?android:attr/listPreferredItemPaddingStart"
+    android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
+    android:paddingTop="8dp"
+    android:paddingBottom="8dp"
+    android:orientation="horizontal">
+
+    <ImageView
+        android:id="@+id/app_icon"
+        android:layout_width="@android:dimen/app_icon_size"
+        android:layout_height="@android:dimen/app_icon_size"
+        android:layout_marginEnd="8dp"
+        android:scaleType="centerInside"
+        android:contentDescription="@null" />
+
+    <TextView
+        android:id="@+id/app_name"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_gravity="fill_horizontal|center_vertical"
+        android:singleLine="true"
+        android:ellipsize="marquee"
+        android:textAppearance="?android:attr/textAppearanceMedium"
+        android:textAlignment="viewStart" />
+
+</LinearLayout>
diff --git a/packages/SystemUI/res/layout/foreground_service_title.xml b/packages/SystemUI/res/layout/foreground_service_title.xml
new file mode 100644
index 0000000..b5434b2
--- /dev/null
+++ b/packages/SystemUI/res/layout/foreground_service_title.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2017, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:orientation="vertical"
+    android:gravity="center_vertical"
+    android:paddingTop="?android:attr/listPreferredItemPaddingStart"
+    android:paddingBottom="16dp"
+    android:paddingStart="?android:attr/listPreferredItemPaddingStart"
+    android:paddingEnd="?android:attr/listPreferredItemPaddingEnd">
+    <com.android.internal.widget.DialogTitle style="?android:attr/textAppearanceLarge"
+        android:singleLine="true"
+        android:ellipsize="end"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:textAlignment="viewStart"
+        android:text="@string/running_foreground_services_title" />
+    <TextView style="?android:attr/textAppearanceSmall"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_marginTop="16dp"
+        android:textAlignment="viewStart"
+        android:text="@string/running_foreground_services_msg" />
+</LinearLayout>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 9097c53..bf70c5a 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -2030,4 +2030,10 @@
     <!-- Do Not Disturb button to change the current settings [CHAR LIMIT=20] -->
     <string name="qs_dnd_replace">Replace</string>
 
+    <!-- Title of the "running foreground services" dialog. [CHAR LIMIT=NONE] -->
+    <string name="running_foreground_services_title">Apps running in background</string>
+
+    <!-- Title of the "running foreground services" dialog. [CHAR LIMIT=NONE] -->
+    <string name="running_foreground_services_msg">Tap for details on battery and data usage</string>
+
 </resources>
diff --git a/packages/SystemUI/src/com/android/systemui/ForegroundServicesDialog.java b/packages/SystemUI/src/com/android/systemui/ForegroundServicesDialog.java
new file mode 100644
index 0000000..086e5e5
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/ForegroundServicesDialog.java
@@ -0,0 +1,204 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.net.Uri;
+import android.os.Bundle;
+import android.provider.Settings;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.AdapterView;
+import android.widget.ArrayAdapter;
+import android.widget.ImageView;
+import android.widget.ListView;
+import android.widget.TextView;
+
+import com.android.internal.app.AlertActivity;
+import com.android.internal.app.AlertController;
+import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.nano.MetricsProto;
+
+import com.android.systemui.R;
+
+import java.util.ArrayList;
+
+/**
+ * Show a list of currently running foreground services (supplied by the caller)
+ * that the user can tap through to their application details.
+ */
+public final class ForegroundServicesDialog extends AlertActivity implements
+        AdapterView.OnItemSelectedListener, DialogInterface.OnClickListener,
+        AlertController.AlertParams.OnPrepareListViewListener {
+
+    private static final String TAG = "ForegroundServicesDialog";
+
+    LayoutInflater mInflater;
+
+    private MetricsLogger mMetricsLogger;
+
+    private String[] mPackages;
+    private PackageItemAdapter mAdapter;
+
+    private DialogInterface.OnClickListener mAppClickListener =
+            new DialogInterface.OnClickListener() {
+                public void onClick(DialogInterface dialog, int which) {
+                    String pkg = mPackages[which];
+                    Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
+                    intent.setData(Uri.fromParts("package", pkg, null));
+                    startActivity(intent);
+                    finish();
+                }
+            };
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        Dependency.initDependencies(getApplicationContext());
+
+        mMetricsLogger = Dependency.get(MetricsLogger.class);
+
+        mInflater = LayoutInflater.from(this);
+
+        mAdapter = new PackageItemAdapter(this);
+
+        final AlertController.AlertParams p = mAlertParams;
+        p.mAdapter = mAdapter;
+        p.mOnClickListener = mAppClickListener;
+        p.mCustomTitleView = mInflater.inflate(R.layout.foreground_service_title, null);
+        p.mIsSingleChoice = true;
+        p.mOnItemSelectedListener = this;
+        p.mPositiveButtonText = getString(com.android.internal.R.string.done_label);
+        p.mPositiveButtonListener = this;
+        p.mOnPrepareListViewListener = this;
+
+        updateApps(getIntent());
+        if (mPackages == null) {
+            Log.w(TAG, "No packages supplied");
+            finish();
+            return;
+        }
+
+        setupAlert();
+    }
+
+    @Override
+    protected void onResume() {
+        super.onResume();
+        mMetricsLogger.visible(MetricsProto.MetricsEvent.RUNNING_BACKGROUND_APPS_DIALOG);
+    }
+
+    @Override
+    protected void onPause() {
+        super.onPause();
+        mMetricsLogger.hidden(MetricsProto.MetricsEvent.RUNNING_BACKGROUND_APPS_DIALOG);
+    }
+
+    @Override
+    protected void onNewIntent(Intent intent) {
+        super.onNewIntent(intent);
+        updateApps(intent);
+    }
+
+    @Override
+    protected void onStop() {
+        super.onStop();
+
+        // This is a transient dialog, if the user leaves it then it goes away,
+        // they can return back to it from the notification.
+        if (!isChangingConfigurations()) {
+            finish();
+        }
+    }
+
+    void updateApps(Intent intent) {
+        mPackages = intent.getStringArrayExtra("packages");
+        if (mPackages != null) {
+            mAdapter.setPackages(mPackages);
+        }
+    }
+
+    public void onPrepareListView(ListView listView) {
+    }
+
+    /*
+     * On click of Ok/Cancel buttons
+     */
+    public void onClick(DialogInterface dialog, int which) {
+        finish();
+    }
+
+    public void onItemSelected(AdapterView parent, View view, int position, long id) {
+    }
+
+    public void onNothingSelected(AdapterView parent) {
+    }
+
+    static private class PackageItemAdapter extends ArrayAdapter<ApplicationInfo> {
+        final PackageManager mPm;
+        final LayoutInflater mInflater;
+
+        public PackageItemAdapter(Context context) {
+            super(context, R.layout.foreground_service_item);
+            mPm = context.getPackageManager();
+            mInflater = LayoutInflater.from(context);
+        }
+
+        public void setPackages(String[] packages) {
+            clear();
+
+            ArrayList<ApplicationInfo> apps = new ArrayList<>();
+            for (int i = 0; i < packages.length; i++) {
+                try {
+                    apps.add(mPm.getApplicationInfo(packages[i],
+                            PackageManager.MATCH_KNOWN_PACKAGES));
+                } catch (PackageManager.NameNotFoundException e) {
+                }
+            }
+
+            apps.sort(new ApplicationInfo.DisplayNameComparator(mPm));
+            addAll(apps);
+        }
+
+        public @NonNull
+        View getView(int position, @Nullable View convertView,
+                @NonNull ViewGroup parent) {
+            final View view;
+            if (convertView == null) {
+                view = mInflater.inflate(R.layout.foreground_service_item, parent, false);
+            } else {
+                view = convertView;
+            }
+
+            ImageView icon = view.findViewById(R.id.app_icon);
+            icon.setImageDrawable(getItem(position).loadIcon(mPm));
+
+            TextView label = view.findViewById(R.id.app_name);
+            label.setText(getItem(position).loadLabel(mPm));
+
+            return view;
+        }
+    }
+}
diff --git a/proto/src/metrics_constants.proto b/proto/src/metrics_constants.proto
index cc6e435..ff99b19 100644
--- a/proto/src/metrics_constants.proto
+++ b/proto/src/metrics_constants.proto
@@ -3952,6 +3952,11 @@
     // internal platform metrics use.
     RESERVED_FOR_LOGBUILDER_UID = 943;
 
+    // OPEN: Running background apps notification > List of background apps
+    // CATEGORY: GLOBAL_SYSTEM_UI
+    // OS: O
+    RUNNING_BACKGROUND_APPS_DIALOG = 944;
+
     // ---- End O Constants, all O constants go above this line ----
 
     // Add new aosp constants above this line.
diff --git a/proto/src/system_messages.proto b/proto/src/system_messages.proto
index 65cc17e..53b3fe9 100644
--- a/proto/src/system_messages.proto
+++ b/proto/src/system_messages.proto
@@ -176,6 +176,10 @@
     // Inform the user their phone recently shut down due to high temperature
     NOTE_THERMAL_SHUTDOWN = 39;
 
+    // Tell the user about currently running foreground services
+    // Package: android
+    NOTE_FOREGROUND_SERVICES = 40;
+
     // ADD_NEW_IDS_ABOVE_THIS_LINE
     // Legacy IDs with arbitrary values appear below
     // Legacy IDs existed as stable non-conflicting constants prior to the O release
diff --git a/services/core/java/com/android/server/DropBoxManagerService.java b/services/core/java/com/android/server/DropBoxManagerService.java
index 9d3d531..e1756d1 100644
--- a/services/core/java/com/android/server/DropBoxManagerService.java
+++ b/services/core/java/com/android/server/DropBoxManagerService.java
@@ -371,6 +371,14 @@
                 doPrint = true;
             } else if (args[i].equals("-f") || args[i].equals("--file")) {
                 doFile = true;
+            } else if (args[i].equals("-h") || args[i].equals("--help")) {
+                pw.println("Dropbox (dropbox) dump options:");
+                pw.println("  [-h|--help] [-p|--print] [-f|--file] [timestamp]");
+                pw.println("    -h|--help: print this help");
+                pw.println("    -p|--print: print full contents of each entry");
+                pw.println("    -f|--file: print path of each entry's file");
+                pw.println("  [timestamp] optionally filters to only those entries.");
+                return;
             } else if (args[i].startsWith("-")) {
                 out.append("Unknown argument: ").append(args[i]).append("\n");
             } else {
diff --git a/services/core/java/com/android/server/InputMethodManagerService.java b/services/core/java/com/android/server/InputMethodManagerService.java
index 8ad3d23..20a6d14 100644
--- a/services/core/java/com/android/server/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/InputMethodManagerService.java
@@ -212,6 +212,7 @@
             Context.BIND_AUTO_CREATE
             | Context.BIND_NOT_VISIBLE
             | Context.BIND_NOT_FOREGROUND
+            | Context.BIND_IMPORTANT_BACKGROUND
             | Context.BIND_SHOWING_UI;
 
     /**
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index d008c5e..5edf19a 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -31,10 +31,12 @@
 
 import android.app.ActivityThread;
 import android.app.AppOpsManager;
+import android.app.NotificationManager;
 import android.app.ServiceStartArgs;
 import android.content.IIntentSender;
 import android.content.IntentSender;
 import android.content.pm.ParceledListSlice;
+import android.net.Uri;
 import android.os.Build;
 import android.os.Bundle;
 import android.os.DeadObjectException;
@@ -43,10 +45,14 @@
 import android.os.RemoteCallback;
 import android.os.SystemProperties;
 import android.os.TransactionTooLargeException;
+import android.provider.Settings;
 import android.util.ArrayMap;
 import android.util.ArraySet;
 
+import com.android.internal.R;
 import com.android.internal.app.procstats.ServiceState;
+import com.android.internal.messages.nano.SystemMessageProto;
+import com.android.internal.notification.SystemNotificationChannels;
 import com.android.internal.os.BatteryStatsImpl;
 import com.android.internal.os.TransferPipe;
 import com.android.internal.util.FastPrintWriter;
@@ -101,32 +107,6 @@
     // calling startForeground() before we ANR + stop it.
     static final int SERVICE_START_FOREGROUND_TIMEOUT = 5*1000;
 
-    // How long a service needs to be running until restarting its process
-    // is no longer considered to be a relaunch of the service.
-    static final int SERVICE_RESTART_DURATION = 1*1000;
-
-    // How long a service needs to be running until it will start back at
-    // SERVICE_RESTART_DURATION after being killed.
-    static final int SERVICE_RESET_RUN_DURATION = 60*1000;
-
-    // Multiplying factor to increase restart duration time by, for each time
-    // a service is killed before it has run for SERVICE_RESET_RUN_DURATION.
-    static final int SERVICE_RESTART_DURATION_FACTOR = 4;
-
-    // The minimum amount of time between restarting services that we allow.
-    // That is, when multiple services are restarting, we won't allow each
-    // to restart less than this amount of time from the last one.
-    static final int SERVICE_MIN_RESTART_TIME_BETWEEN = 10*1000;
-
-    // Maximum amount of time for there to be no activity on a service before
-    // we consider it non-essential and allow its process to go on the
-    // LRU background list.
-    static final int MAX_SERVICE_INACTIVITY = 30*60*1000;
-
-    // How long we wait for a background started service to stop itself before
-    // allowing the next pending start to run.
-    static final int BG_START_TIMEOUT = 15*1000;
-
     final ActivityManagerService mAm;
 
     // Maximum number of services that we allow to start in the background
@@ -162,6 +142,11 @@
     /** Temporary list for holding the results of calls to {@link #collectPackageServicesLocked} */
     private ArrayList<ServiceRecord> mTmpCollectionResults = null;
 
+    /**
+     * For keeping ActiveForegroundApps retaining state while the screen is off.
+     */
+    boolean mScreenOn = true;
+
     /** Amount of time to allow a last ANR message to exist before freeing the memory. */
     static final int LAST_ANR_LIFETIME_DURATION_MSECS = 2 * 60 * 60 * 1000; // Two hours
 
@@ -176,9 +161,23 @@
     };
 
     /**
+     * Information about an app that is currently running one or more foreground services.
+     * (This mapps directly to the running apps we show in the notification.)
+     */
+    static final class ActiveForegroundApp {
+        String mPackageName;
+        CharSequence mLabel;
+        boolean mShownWhileScreenOn;
+        long mStartTime;
+        long mStartVisibleTime;
+        long mEndTime;
+        int mNumActive;
+    }
+
+    /**
      * Information about services for a single user.
      */
-    class ServiceMap extends Handler {
+    final class ServiceMap extends Handler {
         final int mUserId;
         final ArrayMap<ComponentName, ServiceRecord> mServicesByName = new ArrayMap<>();
         final ArrayMap<Intent.FilterComparison, ServiceRecord> mServicesByIntent = new ArrayMap<>();
@@ -196,7 +195,11 @@
 
         final ArrayList<ServiceRecord> mStartingBackground = new ArrayList<>();
 
+        final ArrayMap<String, ActiveForegroundApp> mActiveForegroundApps = new ArrayMap<>();
+        boolean mActiveForegroundAppsChanged;
+
         static final int MSG_BG_START_TIMEOUT = 1;
+        static final int MSG_UPDATE_FOREGROUND_APPS = 2;
 
         ServiceMap(Looper looper, int userId) {
             super(looper);
@@ -211,6 +214,9 @@
                         rescheduleDelayedStartsLocked();
                     }
                 } break;
+                case MSG_UPDATE_FOREGROUND_APPS: {
+                    updateForegroundApps(this);
+                } break;
             }
         }
 
@@ -528,7 +534,7 @@
         if (r.startRequested && addToStarting) {
             boolean first = smap.mStartingBackground.size() == 0;
             smap.mStartingBackground.add(r);
-            r.startingBgTimeout = SystemClock.uptimeMillis() + BG_START_TIMEOUT;
+            r.startingBgTimeout = SystemClock.uptimeMillis() + mAm.mConstants.BG_START_TIMEOUT;
             if (DEBUG_DELAYED_SERVICE) {
                 RuntimeException here = new RuntimeException("here");
                 here.fillInStackTrace();
@@ -716,6 +722,171 @@
         }
     }
 
+    void updateForegroundApps(ServiceMap smap) {
+        // This is called from the handler without the lock held.
+        ArrayList<ActiveForegroundApp> active = null;
+        synchronized (mAm) {
+            final long now = SystemClock.elapsedRealtime();
+            final long nowPlusMin = now + mAm.mConstants.FOREGROUND_SERVICE_UI_MIN_TIME;
+            if (smap != null) {
+                for (int i = smap.mActiveForegroundApps.size()-1; i >= 0; i--) {
+                    ActiveForegroundApp aa = smap.mActiveForegroundApps.valueAt(i);
+                    if (aa.mEndTime != 0 && (mScreenOn || aa.mShownWhileScreenOn)) {
+                        if (aa.mEndTime < (aa.mStartVisibleTime
+                                + mAm.mConstants.FOREGROUND_SERVICE_UI_MIN_TIME)) {
+                            // Check to see if this should still be displayed...  we continue
+                            // until it has been shown for at least the timeout duration.
+                            if (nowPlusMin >= aa.mStartVisibleTime) {
+                                // All over!
+                                smap.mActiveForegroundApps.removeAt(i);
+                                smap.mActiveForegroundAppsChanged = true;
+                                continue;
+                            }
+                        } else {
+                            // This was up for longer than the timeout, so just remove immediately.
+                            smap.mActiveForegroundApps.removeAt(i);
+                            smap.mActiveForegroundAppsChanged = true;
+                            continue;
+                        }
+                    }
+                    if (active == null) {
+                        active = new ArrayList<>();
+                    }
+                    active.add(aa);
+                }
+            }
+            if (!smap.mActiveForegroundAppsChanged) {
+                return;
+            }
+            smap.mActiveForegroundAppsChanged = false;
+        }
+
+        final NotificationManager nm = (NotificationManager) mAm.mContext.getSystemService(
+                Context.NOTIFICATION_SERVICE);
+        final Context context = mAm.mContext;
+
+        if (active != null) {
+            for (int i = 0; i < active.size(); i++) {
+                ActiveForegroundApp aa = active.get(i);
+                if (aa.mLabel == null) {
+                    PackageManager pm = context.getPackageManager();
+                    try {
+                        ApplicationInfo ai = pm.getApplicationInfoAsUser(aa.mPackageName,
+                                PackageManager.MATCH_KNOWN_PACKAGES, smap.mUserId);
+                        aa.mLabel = ai.loadLabel(pm);
+                    } catch (PackageManager.NameNotFoundException e) {
+                        aa.mLabel = aa.mPackageName;
+                    }
+                }
+            }
+
+            Intent intent;
+            String title;
+            String msg;
+            if (active.size() == 1) {
+                intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
+                intent.setData(Uri.fromParts("package", active.get(0).mPackageName, null));
+                title = context.getString(
+                        R.string.foreground_service_app_in_background, active.get(0).mLabel);
+                msg = context.getString(R.string.foreground_service_tap_for_details);
+            } else {
+                intent = new Intent(Settings.ACTION_FOREGROUND_SERVICES_SETTINGS);
+                String[] pkgs = new String[active.size()];
+                for (int i = 0; i < active.size(); i++) {
+                    pkgs[i] = active.get(i).mPackageName;
+                }
+                intent.putExtra("packages", pkgs);
+                title = context.getString(
+                        R.string.foreground_service_apps_in_background, active.size());
+                msg =  active.get(0).mLabel.toString();
+                for (int i = 1; i < active.size(); i++) {
+                    msg = context.getString(R.string.foreground_service_multiple_separator,
+                            msg, active.get(i).mLabel);
+                }
+            }
+            Notification.Builder n =
+                    new Notification.Builder(context,
+                            SystemNotificationChannels.FOREGROUND_SERVICE)
+                            .setSmallIcon(R.drawable.ic_check_circle_24px)
+                            .setOngoing(true)
+                            .setShowWhen(false)
+                            .setColor(context.getColor(
+                                    com.android.internal.R.color.system_notification_accent_color))
+                            .setContentTitle(title)
+                            .setContentText(msg)
+                            .setContentIntent(
+                                    PendingIntent.getActivityAsUser(context, 0, intent,
+                                            PendingIntent.FLAG_UPDATE_CURRENT,
+                                            null, new UserHandle(smap.mUserId)));
+            nm.notifyAsUser(null, SystemMessageProto.SystemMessage.NOTE_FOREGROUND_SERVICES,
+                    n.build(), new UserHandle(smap.mUserId));
+        } else {
+            nm.cancelAsUser(null, SystemMessageProto.SystemMessage.NOTE_FOREGROUND_SERVICES,
+                    new UserHandle(smap.mUserId));
+        }
+    }
+
+    private void requestUpdateActiveForegroundAppsLocked(ServiceMap smap, long time) {
+        Message msg = smap.obtainMessage(ServiceMap.MSG_UPDATE_FOREGROUND_APPS);
+        if (time != 0) {
+            smap.sendMessageAtTime(msg, time);
+        } else {
+            smap.mActiveForegroundAppsChanged = true;
+            smap.sendMessage(msg);
+        }
+    }
+
+    private void decActiveForegroundAppLocked(ServiceMap smap, ServiceRecord r) {
+        ActiveForegroundApp active = smap.mActiveForegroundApps.get(r.packageName);
+        if (active != null) {
+            active.mNumActive--;
+            if (active.mNumActive <= 0) {
+                active.mEndTime = SystemClock.elapsedRealtime();
+                if (active.mEndTime >= (active.mStartVisibleTime
+                        + mAm.mConstants.FOREGROUND_SERVICE_UI_MIN_TIME)) {
+                    // Have been active for long enough that we will remove it immediately.
+                    smap.mActiveForegroundApps.remove(r.packageName);
+                    smap.mActiveForegroundAppsChanged = true;
+                    requestUpdateActiveForegroundAppsLocked(smap, 0);
+                } else {
+                    requestUpdateActiveForegroundAppsLocked(smap, active.mStartVisibleTime
+                            + mAm.mConstants.FOREGROUND_SERVICE_UI_MIN_TIME);
+                }
+            }
+        }
+    }
+
+    void updateScreenStateLocked(boolean screenOn) {
+        if (mScreenOn != screenOn) {
+            mScreenOn = screenOn;
+
+            // If screen is turning on, then we now reset the start time of any foreground
+            // services that were started while the screen was off.
+            if (screenOn) {
+                final long nowElapsed = SystemClock.elapsedRealtime();
+                for (int i = mServiceMap.size()-1; i >= 0; i--) {
+                    ServiceMap smap = mServiceMap.valueAt(i);
+                    boolean changed = false;
+                    for (int j = smap.mActiveForegroundApps.size()-1; j >= 0; j--) {
+                        ActiveForegroundApp active = smap.mActiveForegroundApps.valueAt(j);
+                        if (!active.mShownWhileScreenOn) {
+                            changed = true;
+                            active.mShownWhileScreenOn = mScreenOn;
+                            active.mStartVisibleTime = nowElapsed;
+                            if (active.mEndTime != 0) {
+                                active.mEndTime = nowElapsed;
+                            }
+                        }
+                    }
+                    if (changed) {
+                        requestUpdateActiveForegroundAppsLocked(smap,
+                                nowElapsed + mAm.mConstants.FOREGROUND_SERVICE_UI_MIN_TIME);
+                    }
+                }
+            }
+        }
+    }
+
     private void setServiceForegroundInnerLocked(ServiceRecord r, int id,
             Notification notification, int flags) {
         if (id != 0) {
@@ -770,7 +941,23 @@
             }
             notification.flags |= Notification.FLAG_FOREGROUND_SERVICE;
             r.foregroundNoti = notification;
-            r.isForeground = true;
+            if (!r.isForeground) {
+                final ServiceMap smap = getServiceMapLocked(r.userId);
+                if (smap != null) {
+                    ActiveForegroundApp active = smap.mActiveForegroundApps.get(r.packageName);
+                    if (active == null) {
+                        active = new ActiveForegroundApp();
+                        active.mPackageName = r.packageName;
+                        active.mShownWhileScreenOn = mScreenOn;
+                        active.mStartTime = active.mStartVisibleTime
+                                = SystemClock.elapsedRealtime();
+                        smap.mActiveForegroundApps.put(r.packageName, active);
+                        requestUpdateActiveForegroundAppsLocked(smap, 0);
+                    }
+                    active.mNumActive++;
+                }
+                r.isForeground = true;
+            }
             r.postNotification();
             if (r.app != null) {
                 updateServiceForegroundLocked(r.app, true);
@@ -780,6 +967,10 @@
                                  PackageManager.NOTIFY_PACKAGE_USE_FOREGROUND_SERVICE);
         } else {
             if (r.isForeground) {
+                final ServiceMap smap = getServiceMapLocked(r.userId);
+                if (smap != null) {
+                    decActiveForegroundAppLocked(smap, r);
+                }
                 r.isForeground = false;
                 if (r.app != null) {
                     mAm.updateLruProcessLocked(r.app, false, null);
@@ -1561,8 +1752,8 @@
 
         if ((r.serviceInfo.applicationInfo.flags
                 &ApplicationInfo.FLAG_PERSISTENT) == 0) {
-            long minDuration = SERVICE_RESTART_DURATION;
-            long resetTime = SERVICE_RESET_RUN_DURATION;
+            long minDuration = mAm.mConstants.SERVICE_RESTART_DURATION;
+            long resetTime = mAm.mConstants.SERVICE_RESET_RUN_DURATION;
 
             // Any delivered but not yet finished starts should be put back
             // on the pending list.
@@ -1603,7 +1794,7 @@
                     r.restartCount = 1;
                     r.restartDelay = minDuration;
                 } else {
-                    r.restartDelay *= SERVICE_RESTART_DURATION_FACTOR;
+                    r.restartDelay *= mAm.mConstants.SERVICE_RESTART_DURATION_FACTOR;
                     if (r.restartDelay < minDuration) {
                         r.restartDelay = minDuration;
                     }
@@ -1617,13 +1808,12 @@
             boolean repeat;
             do {
                 repeat = false;
+                final long restartTimeBetween = mAm.mConstants.SERVICE_MIN_RESTART_TIME_BETWEEN;
                 for (int i=mRestartingServices.size()-1; i>=0; i--) {
                     ServiceRecord r2 = mRestartingServices.get(i);
-                    if (r2 != r && r.nextRestartTime
-                            >= (r2.nextRestartTime-SERVICE_MIN_RESTART_TIME_BETWEEN)
-                            && r.nextRestartTime
-                            < (r2.nextRestartTime+SERVICE_MIN_RESTART_TIME_BETWEEN)) {
-                        r.nextRestartTime = r2.nextRestartTime + SERVICE_MIN_RESTART_TIME_BETWEEN;
+                    if (r2 != r && r.nextRestartTime >= (r2.nextRestartTime-restartTimeBetween)
+                            && r.nextRestartTime < (r2.nextRestartTime+restartTimeBetween)) {
+                        r.nextRestartTime = r2.nextRestartTime + restartTimeBetween;
                         r.restartDelay = r.nextRestartTime - now;
                         repeat = true;
                         break;
@@ -2174,6 +2364,9 @@
         }
 
         cancelForegroundNotificationLocked(r);
+        if (r.isForeground) {
+            decActiveForegroundAppLocked(smap, r);
+        }
         r.isForeground = false;
         r.foregroundId = 0;
         r.foregroundNoti = null;
@@ -2612,6 +2805,22 @@
         return didSomething;
     }
 
+    void removeUninstalledPackageLocked(String packageName, int userId) {
+        ServiceMap smap = mServiceMap.get(userId);
+        if (smap != null && smap.mActiveForegroundApps.size() > 0) {
+            for (int i = smap.mActiveForegroundApps.size(); i >= 0; i--) {
+                ActiveForegroundApp aa = smap.mActiveForegroundApps.valueAt(i);
+                if (aa.mPackageName.equals(packageName)) {
+                    smap.mActiveForegroundApps.removeAt(i);
+                    smap.mActiveForegroundAppsChanged = true;
+                }
+            }
+            if (smap.mActiveForegroundAppsChanged) {
+                requestUpdateActiveForegroundAppsLocked(smap, 0);
+            }
+        }
+    }
+
     void cleanUpRemovedTaskLocked(TaskRecord tr, ComponentName component, Intent baseIntent) {
         ArrayList<ServiceRecord> services = new ArrayList<>();
         ArrayMap<ComponentName, ServiceRecord> alls = getServicesLocked(tr.userId);
@@ -3394,6 +3603,55 @@
                 }
             }
 
+            if (matcher.all) {
+                final long nowElapsed = SystemClock.elapsedRealtime();
+                final int[] users = mAm.mUserController.getUsers();
+                for (int user : users) {
+                    boolean printedUser = false;
+                    ServiceMap smap = mServiceMap.get(user);
+                    if (smap == null) {
+                        continue;
+                    }
+                    for (int i = smap.mActiveForegroundApps.size() - 1; i >= 0; i--) {
+                        ActiveForegroundApp aa = smap.mActiveForegroundApps.valueAt(i);
+                        if (dumpPackage != null && !dumpPackage.equals(aa.mPackageName)) {
+                            continue;
+                        }
+                        if (!printedUser) {
+                            printedUser = true;
+                            printedAnything = true;
+                            if (needSep) pw.println();
+                            needSep = true;
+                            pw.print("Active foreground apps - user ");
+                            pw.print(user);
+                            pw.println(":");
+                        }
+                        pw.print("  #");
+                        pw.print(i);
+                        pw.print(": ");
+                        pw.println(aa.mPackageName);
+                        if (aa.mLabel != null) {
+                            pw.print("    mLabel=");
+                            pw.println(aa.mLabel);
+                        }
+                        pw.print("    mNumActive=");
+                        pw.print(aa.mNumActive);
+                        pw.print(" mShownWhileScreenOn=");
+                        pw.println(aa.mShownWhileScreenOn);
+                        pw.print("    mStartTime=");
+                        TimeUtils.formatDuration(aa.mStartTime - nowElapsed, pw);
+                        pw.print(" mStartVisibleTime=");
+                        TimeUtils.formatDuration(aa.mStartVisibleTime - nowElapsed, pw);
+                        pw.println();
+                        if (aa.mEndTime != 0) {
+                            pw.print("    mEndTime=");
+                            TimeUtils.formatDuration(aa.mEndTime - nowElapsed, pw);
+                            pw.println();
+                        }
+                    }
+                }
+            }
+
             if (!printedAnything) {
                 pw.println("  (nothing)");
             }
diff --git a/services/core/java/com/android/server/am/ActivityManagerConstants.java b/services/core/java/com/android/server/am/ActivityManagerConstants.java
index 55ee183..5749f31 100644
--- a/services/core/java/com/android/server/am/ActivityManagerConstants.java
+++ b/services/core/java/com/android/server/am/ActivityManagerConstants.java
@@ -20,25 +20,137 @@
 import android.database.ContentObserver;
 import android.net.Uri;
 import android.os.Handler;
-import android.os.SystemProperties;
 import android.provider.Settings;
 import android.util.KeyValueListParser;
 import android.util.Slog;
 
 import java.io.PrintWriter;
 
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_POWER_QUICK;
+
 /**
  * Settings constants that can modify the activity manager's behavior.
  */
 final class ActivityManagerConstants extends ContentObserver {
     // Key names stored in the settings value.
     private static final String KEY_MAX_CACHED_PROCESSES = "max_cached_processes";
+    private static final String KEY_BACKGROUND_SETTLE_TIME = "background_settle_time";
+    private static final String KEY_FOREGROUND_SERVICE_UI_MIN_TIME
+            = "foreground_service_ui_min_time";
+    private static final String KEY_CONTENT_PROVIDER_RETAIN_TIME = "content_provider_retain_time";
+    private static final String KEY_GC_TIMEOUT = "gc_timeout";
+    private static final String KEY_GC_MIN_INTERVAL = "gc_min_interval";
+    private static final String KEY_FULL_PSS_MIN_INTERVAL = "full_pss_min_interval";
+    private static final String KEY_FULL_PSS_LOWERED_INTERVAL = "full_pss_lowered_interval";
+    private static final String KEY_POWER_CHECK_DELAY = "power_check_delay";
+    private static final String KEY_WAKE_LOCK_MIN_CHECK_DURATION = "wake_lock_min_check_duration";
+    private static final String KEY_CPU_MIN_CHECK_DURATION = "cpu_min_check_duration";
+    private static final String KEY_SERVICE_USAGE_INTERACTION_TIME
+            = "service_usage_interaction_time";
+    private static final String KEY_USAGE_STATS_INTERACTION_INTERVAL
+            = "usage_stats_interaction_interval";
+    static final String KEY_SERVICE_RESTART_DURATION = "service_restart_duration";
+    static final String KEY_SERVICE_RESET_RUN_DURATION = "service_reset_run_duration";
+    static final String KEY_SERVICE_RESTART_DURATION_FACTOR = "service_restart_duration_factor";
+    static final String KEY_SERVICE_MIN_RESTART_TIME_BETWEEN = "service_min_restart_time_between";
+    static final String KEY_MAX_SERVICE_INACTIVITY = "service_max_inactivity";
+    static final String KEY_BG_START_TIMEOUT = "service_bg_start_timeout";
 
     private static final int DEFAULT_MAX_CACHED_PROCESSES = 32;
+    private static final long DEFAULT_BACKGROUND_SETTLE_TIME = 60*1000;
+    private static final long DEFAULT_FOREGROUND_SERVICE_UI_MIN_TIME = 30*1000;
+    private static final long DEFAULT_CONTENT_PROVIDER_RETAIN_TIME = 20*1000;
+    private static final long DEFAULT_GC_TIMEOUT = 5*1000;
+    private static final long DEFAULT_GC_MIN_INTERVAL = 60*1000;
+    private static final long DEFAULT_FULL_PSS_MIN_INTERVAL = 10*60*1000;
+    private static final long DEFAULT_FULL_PSS_LOWERED_INTERVAL = 2*60*1000;
+    private static final long DEFAULT_POWER_CHECK_DELAY = (DEBUG_POWER_QUICK ? 2 : 15) * 60*1000;
+    private static final long DEFAULT_WAKE_LOCK_MIN_CHECK_DURATION
+            = (DEBUG_POWER_QUICK ? 1 : 5) * 60*1000;
+    private static final long DEFAULT_CPU_MIN_CHECK_DURATION
+            = (DEBUG_POWER_QUICK ? 1 : 5) * 60*1000;
+    private static final long DEFAULT_SERVICE_USAGE_INTERACTION_TIME = 30*60*1000;
+    private static final long DEFAULT_USAGE_STATS_INTERACTION_INTERVAL = 24*60*60*1000L;
+    private static final long DEFAULT_SERVICE_RESTART_DURATION = 1*1000;
+    private static final long DEFAULT_SERVICE_RESET_RUN_DURATION = 60*1000;
+    private static final int DEFAULT_SERVICE_RESTART_DURATION_FACTOR = 4;
+    private static final long DEFAULT_SERVICE_MIN_RESTART_TIME_BETWEEN = 10*1000;
+    private static final long DEFAULT_MAX_SERVICE_INACTIVITY = 30*60*1000;
+    private static final long DEFAULT_BG_START_TIMEOUT = 15*1000;
 
     // Maximum number of cached processes we will allow.
     public int MAX_CACHED_PROCESSES = DEFAULT_MAX_CACHED_PROCESSES;
 
+    // This is the amount of time we allow an app to settle after it goes into the background,
+    // before we start restricting what it can do.
+    public long BACKGROUND_SETTLE_TIME = DEFAULT_BACKGROUND_SETTLE_TIME;
+
+    // The minimum time a foreground service will be shown as running in the notification UI.
+    public long FOREGROUND_SERVICE_UI_MIN_TIME = DEFAULT_FOREGROUND_SERVICE_UI_MIN_TIME;
+
+    // How long we will retain processes hosting content providers in the "last activity"
+    // state before allowing them to drop down to the regular cached LRU list.  This is
+    // to avoid thrashing of provider processes under low memory situations.
+    long CONTENT_PROVIDER_RETAIN_TIME = DEFAULT_CONTENT_PROVIDER_RETAIN_TIME;
+
+    // How long to wait after going idle before forcing apps to GC.
+    long GC_TIMEOUT = DEFAULT_GC_TIMEOUT;
+
+    // The minimum amount of time between successive GC requests for a process.
+    long GC_MIN_INTERVAL = DEFAULT_GC_MIN_INTERVAL;
+
+    // The minimum amount of time between successive PSS requests for a process.
+    long FULL_PSS_MIN_INTERVAL = DEFAULT_FULL_PSS_MIN_INTERVAL;
+
+    // The minimum amount of time between successive PSS requests for a process
+    // when the request is due to the memory state being lowered.
+    long FULL_PSS_LOWERED_INTERVAL = DEFAULT_FULL_PSS_LOWERED_INTERVAL;
+
+    // The rate at which we check for apps using excessive power -- 15 mins.
+    long POWER_CHECK_DELAY = DEFAULT_POWER_CHECK_DELAY;
+
+    // The minimum sample duration we will allow before deciding we have
+    // enough data on wake locks to start killing things.
+    long WAKE_LOCK_MIN_CHECK_DURATION = DEFAULT_WAKE_LOCK_MIN_CHECK_DURATION;
+
+    // The minimum sample duration we will allow before deciding we have
+    // enough data on CPU usage to start killing things.
+    long CPU_MIN_CHECK_DURATION = DEFAULT_CPU_MIN_CHECK_DURATION;
+
+    // This is the amount of time an app needs to be running a foreground service before
+    // we will consider it to be doing interaction for usage stats.
+    long SERVICE_USAGE_INTERACTION_TIME = DEFAULT_SERVICE_USAGE_INTERACTION_TIME;
+
+    // Maximum amount of time we will allow to elapse before re-reporting usage stats
+    // interaction with foreground processes.
+    long USAGE_STATS_INTERACTION_INTERVAL = DEFAULT_USAGE_STATS_INTERACTION_INTERVAL;
+
+    // How long a service needs to be running until restarting its process
+    // is no longer considered to be a relaunch of the service.
+    public long SERVICE_RESTART_DURATION = DEFAULT_SERVICE_RESTART_DURATION;
+
+    // How long a service needs to be running until it will start back at
+    // SERVICE_RESTART_DURATION after being killed.
+    public long SERVICE_RESET_RUN_DURATION = DEFAULT_SERVICE_RESET_RUN_DURATION;
+
+    // Multiplying factor to increase restart duration time by, for each time
+    // a service is killed before it has run for SERVICE_RESET_RUN_DURATION.
+    public int SERVICE_RESTART_DURATION_FACTOR = DEFAULT_SERVICE_RESTART_DURATION_FACTOR;
+
+    // The minimum amount of time between restarting services that we allow.
+    // That is, when multiple services are restarting, we won't allow each
+    // to restart less than this amount of time from the last one.
+    public long SERVICE_MIN_RESTART_TIME_BETWEEN = DEFAULT_SERVICE_MIN_RESTART_TIME_BETWEEN;
+
+    // Maximum amount of time for there to be no activity on a service before
+    // we consider it non-essential and allow its process to go on the
+    // LRU background list.
+    public long MAX_SERVICE_INACTIVITY = DEFAULT_MAX_SERVICE_INACTIVITY;
+
+    // How long we wait for a background started service to stop itself before
+    // allowing the next pending start to run.
+    public long BG_START_TIMEOUT = DEFAULT_BG_START_TIMEOUT;
+
     private final ActivityManagerService mService;
     private ContentResolver mResolver;
     private final KeyValueListParser mParser = new KeyValueListParser(',');
@@ -111,6 +223,42 @@
             }
             MAX_CACHED_PROCESSES = mParser.getInt(KEY_MAX_CACHED_PROCESSES,
                     DEFAULT_MAX_CACHED_PROCESSES);
+            BACKGROUND_SETTLE_TIME = mParser.getLong(KEY_BACKGROUND_SETTLE_TIME,
+                    DEFAULT_BACKGROUND_SETTLE_TIME);
+            FOREGROUND_SERVICE_UI_MIN_TIME = mParser.getLong(KEY_FOREGROUND_SERVICE_UI_MIN_TIME,
+                    DEFAULT_FOREGROUND_SERVICE_UI_MIN_TIME);
+            CONTENT_PROVIDER_RETAIN_TIME = mParser.getLong(KEY_CONTENT_PROVIDER_RETAIN_TIME,
+                    DEFAULT_CONTENT_PROVIDER_RETAIN_TIME);
+            GC_TIMEOUT = mParser.getLong(KEY_GC_TIMEOUT,
+                    DEFAULT_GC_TIMEOUT);
+            GC_MIN_INTERVAL = mParser.getLong(KEY_GC_MIN_INTERVAL,
+                    DEFAULT_GC_MIN_INTERVAL);
+            FULL_PSS_MIN_INTERVAL = mParser.getLong(KEY_FULL_PSS_MIN_INTERVAL,
+                    DEFAULT_FULL_PSS_MIN_INTERVAL);
+            FULL_PSS_LOWERED_INTERVAL = mParser.getLong(KEY_FULL_PSS_LOWERED_INTERVAL,
+                    DEFAULT_FULL_PSS_LOWERED_INTERVAL);
+            POWER_CHECK_DELAY = mParser.getLong(KEY_POWER_CHECK_DELAY,
+                    DEFAULT_POWER_CHECK_DELAY);
+            WAKE_LOCK_MIN_CHECK_DURATION = mParser.getLong(KEY_WAKE_LOCK_MIN_CHECK_DURATION,
+                    DEFAULT_WAKE_LOCK_MIN_CHECK_DURATION);
+            CPU_MIN_CHECK_DURATION = mParser.getLong(KEY_CPU_MIN_CHECK_DURATION,
+                    DEFAULT_CPU_MIN_CHECK_DURATION);
+            SERVICE_USAGE_INTERACTION_TIME = mParser.getLong(KEY_SERVICE_USAGE_INTERACTION_TIME,
+                    DEFAULT_SERVICE_USAGE_INTERACTION_TIME);
+            USAGE_STATS_INTERACTION_INTERVAL = mParser.getLong(KEY_USAGE_STATS_INTERACTION_INTERVAL,
+                    DEFAULT_USAGE_STATS_INTERACTION_INTERVAL);
+            SERVICE_RESTART_DURATION = mParser.getLong(KEY_SERVICE_RESTART_DURATION,
+                    DEFAULT_SERVICE_RESTART_DURATION);
+            SERVICE_RESET_RUN_DURATION = mParser.getLong(KEY_SERVICE_RESET_RUN_DURATION,
+                    DEFAULT_SERVICE_RESET_RUN_DURATION);
+            SERVICE_RESTART_DURATION_FACTOR = mParser.getInt(KEY_SERVICE_RESTART_DURATION_FACTOR,
+                    DEFAULT_SERVICE_RESTART_DURATION_FACTOR);
+            SERVICE_MIN_RESTART_TIME_BETWEEN = mParser.getLong(KEY_SERVICE_MIN_RESTART_TIME_BETWEEN,
+                    DEFAULT_SERVICE_MIN_RESTART_TIME_BETWEEN);
+            MAX_SERVICE_INACTIVITY = mParser.getLong(KEY_MAX_SERVICE_INACTIVITY,
+                    DEFAULT_MAX_SERVICE_INACTIVITY);
+            BG_START_TIMEOUT = mParser.getLong(KEY_BG_START_TIMEOUT,
+                    DEFAULT_BG_START_TIMEOUT);
             updateMaxCachedProcesses();
         }
     }
@@ -134,6 +282,42 @@
 
         pw.print("  "); pw.print(KEY_MAX_CACHED_PROCESSES); pw.print("=");
         pw.println(MAX_CACHED_PROCESSES);
+        pw.print("  "); pw.print(KEY_BACKGROUND_SETTLE_TIME); pw.print("=");
+        pw.println(BACKGROUND_SETTLE_TIME);
+        pw.print("  "); pw.print(KEY_FOREGROUND_SERVICE_UI_MIN_TIME); pw.print("=");
+        pw.println(FOREGROUND_SERVICE_UI_MIN_TIME);
+        pw.print("  "); pw.print(KEY_CONTENT_PROVIDER_RETAIN_TIME); pw.print("=");
+        pw.println(CONTENT_PROVIDER_RETAIN_TIME);
+        pw.print("  "); pw.print(KEY_GC_TIMEOUT); pw.print("=");
+        pw.println(GC_TIMEOUT);
+        pw.print("  "); pw.print(KEY_GC_MIN_INTERVAL); pw.print("=");
+        pw.println(GC_MIN_INTERVAL);
+        pw.print("  "); pw.print(KEY_FULL_PSS_MIN_INTERVAL); pw.print("=");
+        pw.println(FULL_PSS_MIN_INTERVAL);
+        pw.print("  "); pw.print(KEY_FULL_PSS_LOWERED_INTERVAL); pw.print("=");
+        pw.println(FULL_PSS_LOWERED_INTERVAL);
+        pw.print("  "); pw.print(KEY_POWER_CHECK_DELAY); pw.print("=");
+        pw.println(POWER_CHECK_DELAY);
+        pw.print("  "); pw.print(KEY_WAKE_LOCK_MIN_CHECK_DURATION); pw.print("=");
+        pw.println(WAKE_LOCK_MIN_CHECK_DURATION);
+        pw.print("  "); pw.print(KEY_CPU_MIN_CHECK_DURATION); pw.print("=");
+        pw.println(CPU_MIN_CHECK_DURATION);
+        pw.print("  "); pw.print(KEY_SERVICE_USAGE_INTERACTION_TIME); pw.print("=");
+        pw.println(SERVICE_USAGE_INTERACTION_TIME);
+        pw.print("  "); pw.print(KEY_USAGE_STATS_INTERACTION_INTERVAL); pw.print("=");
+        pw.println(USAGE_STATS_INTERACTION_INTERVAL);
+        pw.print("  "); pw.print(KEY_SERVICE_RESTART_DURATION); pw.print("=");
+        pw.println(SERVICE_RESTART_DURATION);
+        pw.print("  "); pw.print(KEY_SERVICE_RESET_RUN_DURATION); pw.print("=");
+        pw.println(SERVICE_RESET_RUN_DURATION);
+        pw.print("  "); pw.print(KEY_SERVICE_RESTART_DURATION_FACTOR); pw.print("=");
+        pw.println(SERVICE_RESTART_DURATION_FACTOR);
+        pw.print("  "); pw.print(KEY_SERVICE_MIN_RESTART_TIME_BETWEEN); pw.print("=");
+        pw.println(SERVICE_MIN_RESTART_TIME_BETWEEN);
+        pw.print("  "); pw.print(KEY_MAX_SERVICE_INACTIVITY); pw.print("=");
+        pw.println(MAX_SERVICE_INACTIVITY);
+        pw.print("  "); pw.print(KEY_BG_START_TIMEOUT); pw.print("=");
+        pw.println(BG_START_TIMEOUT);
 
         pw.println();
         if (mOverrideMaxCachedProcesses >= 0) {
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 71ef230..d46a24b 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -513,41 +513,12 @@
     // before we decide it must be hung.
     static final int CONTENT_PROVIDER_PUBLISH_TIMEOUT = 10*1000;
 
-    // How long we will retain processes hosting content providers in the "last activity"
-    // state before allowing them to drop down to the regular cached LRU list.  This is
-    // to avoid thrashing of provider processes under low memory situations.
-    static final int CONTENT_PROVIDER_RETAIN_TIME = 20*1000;
-
     // How long we wait for a launched process to attach to the activity manager
     // before we decide it's never going to come up for real, when the process was
     // started with a wrapper for instrumentation (such as Valgrind) because it
     // could take much longer than usual.
     static final int PROC_START_TIMEOUT_WITH_WRAPPER = 1200*1000;
 
-    // How long to wait after going idle before forcing apps to GC.
-    static final int GC_TIMEOUT = 5*1000;
-
-    // The minimum amount of time between successive GC requests for a process.
-    static final int GC_MIN_INTERVAL = 60*1000;
-
-    // The minimum amount of time between successive PSS requests for a process.
-    static final int FULL_PSS_MIN_INTERVAL = 10*60*1000;
-
-    // The minimum amount of time between successive PSS requests for a process
-    // when the request is due to the memory state being lowered.
-    static final int FULL_PSS_LOWERED_INTERVAL = 2*60*1000;
-
-    // The rate at which we check for apps using excessive power -- 15 mins.
-    static final int POWER_CHECK_DELAY = (DEBUG_POWER_QUICK ? 2 : 15) * 60*1000;
-
-    // The minimum sample duration we will allow before deciding we have
-    // enough data on wake locks to start killing things.
-    static final int WAKE_LOCK_MIN_CHECK_DURATION = (DEBUG_POWER_QUICK ? 1 : 5) * 60*1000;
-
-    // The minimum sample duration we will allow before deciding we have
-    // enough data on CPU usage to start killing things.
-    static final int CPU_MIN_CHECK_DURATION = (DEBUG_POWER_QUICK ? 1 : 5) * 60*1000;
-
     // How long we allow a receiver to run before giving up on it.
     static final int BROADCAST_FG_TIMEOUT = 10*1000;
     static final int BROADCAST_BG_TIMEOUT = 60*1000;
@@ -558,18 +529,6 @@
     // How long we wait until we timeout on key dispatching during instrumentation.
     static final int INSTRUMENTATION_KEY_DISPATCHING_TIMEOUT = 60*1000;
 
-    // This is the amount of time an app needs to be running a foreground service before
-    // we will consider it to be doing interaction for usage stats.
-    static final int SERVICE_USAGE_INTERACTION_TIME = 30*60*1000;
-
-    // Maximum amount of time we will allow to elapse before re-reporting usage stats
-    // interaction with foreground processes.
-    static final long USAGE_STATS_INTERACTION_INTERVAL = 24*60*60*1000L;
-
-    // This is the amount of time we allow an app to settle after it goes into the background,
-    // before we start restricting what it can do.
-    static final int BACKGROUND_SETTLE_TIME = 1*60*1000;
-
     // How long to wait in getAssistContextExtras for the activity and foreground services
     // to respond with the result.
     static final int PENDING_ASSIST_EXTRAS_TIMEOUT = 500;
@@ -2147,7 +2106,7 @@
                     checkExcessivePowerUsageLocked(true);
                     removeMessages(CHECK_EXCESSIVE_WAKE_LOCKS_MSG);
                     Message nmsg = obtainMessage(CHECK_EXCESSIVE_WAKE_LOCKS_MSG);
-                    sendMessageDelayed(nmsg, POWER_CHECK_DELAY);
+                    sendMessageDelayed(nmsg, mConstants.POWER_CHECK_DELAY);
                 }
             } break;
             case REPORT_MEM_USAGE_MSG: {
@@ -4259,7 +4218,7 @@
                         "Unable to set a higher trim level than current level");
             }
             if (!(level < ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN ||
-                    app.curProcState >= ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND)) {
+                    app.curProcState > ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND)) {
                 throw new IllegalArgumentException("Unable to set a background trim level "
                     + "on a foreground process");
             }
@@ -5345,7 +5304,7 @@
                     memInfos.add(new ProcessMemInfo(rec.processName, rec.pid, rec.setAdj,
                             rec.setProcState, rec.adjType, rec.makeAdjReason()));
                 }
-                if ((rec.lastLowMemory+GC_MIN_INTERVAL) <= now) {
+                if ((rec.lastLowMemory+mConstants.GC_MIN_INTERVAL) <= now) {
                     // The low memory report is overriding any current
                     // state for a GC request.  Make sure to do
                     // heavy/important/visible/foreground processes first.
@@ -7103,7 +7062,7 @@
             if (mFactoryTest != FactoryTest.FACTORY_TEST_LOW_LEVEL) {
                 // Start looking for apps that are abusing wake locks.
                 Message nmsg = mHandler.obtainMessage(CHECK_EXCESSIVE_WAKE_LOCKS_MSG);
-                mHandler.sendMessageDelayed(nmsg, POWER_CHECK_DELAY);
+                mHandler.sendMessageDelayed(nmsg, mConstants.POWER_CHECK_DELAY);
                 // Tell anyone interested that we are done booting!
                 SystemProperties.set("sys.boot_completed", "1");
 
@@ -12277,14 +12236,15 @@
     }
 
     void updateSleepIfNeededLocked() {
-        if (mSleeping && !shouldSleepLocked()) {
+        final boolean shouldSleep = shouldSleepLocked();
+        if (mSleeping && !shouldSleep) {
             mSleeping = false;
             startTimeTrackingFocusedActivityLocked();
             mTopProcessState = ActivityManager.PROCESS_STATE_TOP;
             mStackSupervisor.comeOutOfSleepIfNeededLocked();
             sendNotifyVrManagerOfSleepState(false);
             updateOomAdjLocked();
-        } else if (!mSleeping && shouldSleepLocked()) {
+        } else if (!mSleeping && shouldSleep) {
             mSleeping = true;
             if (mCurAppTimeTracker != null) {
                 mCurAppTimeTracker.stop();
@@ -12298,7 +12258,20 @@
             checkExcessivePowerUsageLocked(false);
             mHandler.removeMessages(CHECK_EXCESSIVE_WAKE_LOCKS_MSG);
             Message nmsg = mHandler.obtainMessage(CHECK_EXCESSIVE_WAKE_LOCKS_MSG);
-            mHandler.sendMessageDelayed(nmsg, POWER_CHECK_DELAY);
+            mHandler.sendMessageDelayed(nmsg, mConstants.POWER_CHECK_DELAY);
+        }
+
+        // Also update state in a special way for running foreground services UI.
+        switch (mWakefulness) {
+            case PowerManagerInternal.WAKEFULNESS_ASLEEP:
+            case PowerManagerInternal.WAKEFULNESS_DREAMING:
+            case PowerManagerInternal.WAKEFULNESS_DOZING:
+                mServices.updateScreenStateLocked(false);
+                break;
+            case PowerManagerInternal.WAKEFULNESS_AWAKE:
+            default:
+                mServices.updateScreenStateLocked(true);
+                break;
         }
     }
 
@@ -19034,6 +19007,8 @@
 
                                         removeTasksByPackageNameLocked(ssp, userId);
 
+                                        mServices.removeUninstalledPackageLocked(ssp, userId);
+
                                         // Hide the "unsupported display" dialog if necessary.
                                         if (mUnsupportedDisplaySizeDialog != null && ssp.equals(
                                                 mUnsupportedDisplaySizeDialog.getPackageName())) {
@@ -20823,8 +20798,8 @@
             if (adj > ProcessList.BACKUP_APP_ADJ) {
                 if (DEBUG_BACKUP) Slog.v(TAG_BACKUP, "oom BACKUP_APP_ADJ for " + app);
                 adj = ProcessList.BACKUP_APP_ADJ;
-                if (procState > ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND) {
-                    procState = ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND;
+                if (procState > ActivityManager.PROCESS_STATE_TRANSIENT_BACKGROUND) {
+                    procState = ActivityManager.PROCESS_STATE_TRANSIENT_BACKGROUND;
                 }
                 app.adjType = "backup";
                 app.cached = false;
@@ -20856,7 +20831,7 @@
                         app.adjType = "cch-started-ui-services";
                     }
                 } else {
-                    if (now < (s.lastActivity + ActiveServices.MAX_SERVICE_INACTIVITY)) {
+                    if (now < (s.lastActivity + mConstants.MAX_SERVICE_INACTIVITY)) {
                         // This service has seen some activity within
                         // recent memory, so we will keep its process ahead
                         // of the background processes.
@@ -20921,8 +20896,7 @@
                                 clientAdj = adj;
                                 clientProcState = procState;
                             } else {
-                                if (now >= (s.lastActivity
-                                        + ActiveServices.MAX_SERVICE_INACTIVITY)) {
+                                if (now >= (s.lastActivity + mConstants.MAX_SERVICE_INACTIVITY)) {
                                     // This service has not seen activity within
                                     // recent memory, so allow it to drop to the
                                     // LRU list if there is no other reason to keep
@@ -20968,7 +20942,8 @@
                                 adjType = "service";
                             }
                         }
-                        if ((cr.flags&Context.BIND_NOT_FOREGROUND) == 0) {
+                        if ((cr.flags & (Context.BIND_NOT_FOREGROUND
+                                | Context.BIND_IMPORTANT_BACKGROUND)) == 0) {
                             // This will treat important bound services identically to
                             // the top app, which may behave differently than generic
                             // foreground work.
@@ -21012,6 +20987,12 @@
                                     }
                                 }
                             }
+                        } else if ((cr.flags & Context.BIND_IMPORTANT_BACKGROUND) == 0) {
+                            if (clientProcState <
+                                    ActivityManager.PROCESS_STATE_TRANSIENT_BACKGROUND) {
+                                clientProcState =
+                                        ActivityManager.PROCESS_STATE_TRANSIENT_BACKGROUND;
+                            }
                         } else {
                             if (clientProcState <
                                     ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND) {
@@ -21150,7 +21131,8 @@
             }
         }
 
-        if (app.lastProviderTime > 0 && (app.lastProviderTime+CONTENT_PROVIDER_RETAIN_TIME) > now) {
+        if (app.lastProviderTime > 0 &&
+                (app.lastProviderTime+mConstants.CONTENT_PROVIDER_RETAIN_TIME) > now) {
             if (adj > ProcessList.PREVIOUS_APP_ADJ) {
                 adj = ProcessList.PREVIOUS_APP_ADJ;
                 schedGroup = ProcessList.SCHED_GROUP_BACKGROUND;
@@ -21172,6 +21154,7 @@
             switch (procState) {
                 case ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND:
                 case ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND:
+                case ActivityManager.PROCESS_STATE_TRANSIENT_BACKGROUND:
                 case ActivityManager.PROCESS_STATE_SERVICE:
                     // These all are longer-term states, so pull them up to the top
                     // of the background states, but not all the way to the top state.
@@ -21367,7 +21350,8 @@
     void requestPssAllProcsLocked(long now, boolean always, boolean memLowered) {
         if (!always) {
             if (now < (mLastFullPssTime +
-                    (memLowered ? FULL_PSS_LOWERED_INTERVAL : FULL_PSS_MIN_INTERVAL))) {
+                    (memLowered ? mConstants.FULL_PSS_LOWERED_INTERVAL
+                            : mConstants.FULL_PSS_MIN_INTERVAL))) {
                 return;
             }
         }
@@ -21449,7 +21433,7 @@
             while (mProcessesToGc.size() > 0) {
                 ProcessRecord proc = mProcessesToGc.remove(0);
                 if (proc.curRawAdj > ProcessList.PERCEPTIBLE_APP_ADJ || proc.reportLowMemory) {
-                    if ((proc.lastRequestedGc+GC_MIN_INTERVAL)
+                    if ((proc.lastRequestedGc+mConstants.GC_MIN_INTERVAL)
                             <= SystemClock.uptimeMillis()) {
                         // To avoid spamming the system, we will GC processes one
                         // at a time, waiting a few seconds between each.
@@ -21492,10 +21476,10 @@
             ProcessRecord proc = mProcessesToGc.get(0);
             Message msg = mHandler.obtainMessage(GC_BACKGROUND_PROCESSES_MSG);
 
-            long when = proc.lastRequestedGc + GC_MIN_INTERVAL;
+            long when = proc.lastRequestedGc + mConstants.GC_MIN_INTERVAL;
             long now = SystemClock.uptimeMillis();
-            if (when < (now+GC_TIMEOUT)) {
-                when = now + GC_TIMEOUT;
+            if (when < (now+mConstants.GC_TIMEOUT)) {
+                when = now + mConstants.GC_TIMEOUT;
             }
             mHandler.sendMessageAtTime(msg, when);
         }
@@ -21528,7 +21512,7 @@
      */
     final void scheduleAppGcLocked(ProcessRecord app) {
         long now = SystemClock.uptimeMillis();
-        if ((app.lastRequestedGc+GC_MIN_INTERVAL) > now) {
+        if ((app.lastRequestedGc+mConstants.GC_MIN_INTERVAL) > now) {
             return;
         }
         if (!mProcessesToGc.contains(app)) {
@@ -21558,10 +21542,10 @@
         final long uptimeSince = curUptime - mLastPowerCheckUptime;
         mLastPowerCheckRealtime = curRealtime;
         mLastPowerCheckUptime = curUptime;
-        if (realtimeSince < WAKE_LOCK_MIN_CHECK_DURATION) {
+        if (realtimeSince < mConstants.WAKE_LOCK_MIN_CHECK_DURATION) {
             doWakeKills = false;
         }
-        if (uptimeSince < CPU_MIN_CHECK_DURATION) {
+        if (uptimeSince < mConstants.CPU_MIN_CHECK_DURATION) {
             doCpuKills = false;
         }
         int i = mLruProcesses.size();
@@ -21819,7 +21803,7 @@
                 app.procStateChanged = true;
             }
         } else if (app.reportedInteraction && (nowElapsed-app.interactionEventTime)
-                > USAGE_STATS_INTERACTION_INTERVAL) {
+                > mConstants.USAGE_STATS_INTERACTION_INTERVAL) {
             // For apps that sit around for a long time in the interactive state, we need
             // to report this at least once a day so they don't go idle.
             maybeUpdateUsageStatsLocked(app, nowElapsed);
@@ -21992,7 +21976,8 @@
                 app.fgInteractionTime = nowElapsed;
                 isInteraction = false;
             } else {
-                isInteraction = nowElapsed > app.fgInteractionTime + SERVICE_USAGE_INTERACTION_TIME;
+                isInteraction = nowElapsed > app.fgInteractionTime
+                        + mConstants.SERVICE_USAGE_INTERACTION_TIME;
             }
         } else {
             // If the app was being forced to the foreground, by say a Toast, then
@@ -22001,8 +21986,8 @@
                     && app.curProcState <= ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND;
             app.fgInteractionTime = 0;
         }
-        if (isInteraction && (!app.reportedInteraction
-                || (nowElapsed-app.interactionEventTime) > USAGE_STATS_INTERACTION_INTERVAL)) {
+        if (isInteraction && (!app.reportedInteraction || (nowElapsed-app.interactionEventTime)
+                > mConstants.USAGE_STATS_INTERACTION_INTERVAL)) {
             app.interactionEventTime = nowElapsed;
             String[] packages = app.getPackageList();
             if (packages != null) {
@@ -22518,7 +22503,8 @@
                             // the handler time base is uptime.  All this means is that we may
                             // stop background uids later than we had intended, but that only
                             // happens because the device was sleeping so we are okay anyway.
-                            mHandler.sendEmptyMessageDelayed(IDLE_UIDS_MSG, BACKGROUND_SETTLE_TIME);
+                            mHandler.sendEmptyMessageDelayed(IDLE_UIDS_MSG,
+                                    mConstants.BACKGROUND_SETTLE_TIME);
                         }
                     }
                 } else {
@@ -22623,7 +22609,7 @@
                 return;
             }
             final long nowElapsed = SystemClock.elapsedRealtime();
-            final long maxBgTime = nowElapsed - BACKGROUND_SETTLE_TIME;
+            final long maxBgTime = nowElapsed - mConstants.BACKGROUND_SETTLE_TIME;
             long nextTime = 0;
             if (mLocalPowerManager != null) {
                 mLocalPowerManager.startUidChanges();
@@ -22648,7 +22634,7 @@
             if (nextTime > 0) {
                 mHandler.removeMessages(IDLE_UIDS_MSG);
                 mHandler.sendEmptyMessageDelayed(IDLE_UIDS_MSG,
-                        nextTime + BACKGROUND_SETTLE_TIME - nowElapsed);
+                        nextTime + mConstants.BACKGROUND_SETTLE_TIME - nowElapsed);
             }
         }
     }
diff --git a/services/core/java/com/android/server/am/ConnectionRecord.java b/services/core/java/com/android/server/am/ConnectionRecord.java
index cd37041..9b7a0c4 100644
--- a/services/core/java/com/android/server/am/ConnectionRecord.java
+++ b/services/core/java/com/android/server/am/ConnectionRecord.java
@@ -74,6 +74,9 @@
         if ((flags&Context.BIND_NOT_FOREGROUND) != 0) {
             sb.append("!FG ");
         }
+        if ((flags&Context.BIND_IMPORTANT_BACKGROUND) != 0) {
+            sb.append("IMPB ");
+        }
         if ((flags&Context.BIND_ABOVE_CLIENT) != 0) {
             sb.append("ABCLT ");
         }
diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java
index 0dc6788..80e7c75 100644
--- a/services/core/java/com/android/server/am/ProcessList.java
+++ b/services/core/java/com/android/server/am/ProcessList.java
@@ -373,6 +373,9 @@
             case ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND:
                 procState = "IMPB";
                 break;
+            case ActivityManager.PROCESS_STATE_TRANSIENT_BACKGROUND:
+                procState = "TRNB";
+                break;
             case ActivityManager.PROCESS_STATE_BACKUP:
                 procState = "BKUP";
                 break;
@@ -482,6 +485,7 @@
         PROC_MEM_TOP,                   // ActivityManager.PROCESS_STATE_TOP_SLEEPING
         PROC_MEM_IMPORTANT,             // ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND
         PROC_MEM_IMPORTANT,             // ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND
+        PROC_MEM_IMPORTANT,             // ActivityManager.PROCESS_STATE_TRANSIENT_BACKGROUND
         PROC_MEM_IMPORTANT,             // ActivityManager.PROCESS_STATE_BACKUP
         PROC_MEM_IMPORTANT,             // ActivityManager.PROCESS_STATE_HEAVY_WEIGHT
         PROC_MEM_SERVICE,               // ActivityManager.PROCESS_STATE_SERVICE
@@ -502,6 +506,7 @@
         PSS_FIRST_BACKGROUND_INTERVAL,  // ActivityManager.PROCESS_STATE_TOP_SLEEPING
         PSS_FIRST_BACKGROUND_INTERVAL,  // ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND
         PSS_FIRST_BACKGROUND_INTERVAL,  // ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND
+        PSS_FIRST_BACKGROUND_INTERVAL,  // ActivityManager.PROCESS_STATE_TRANSIENT_BACKGROUND
         PSS_FIRST_BACKGROUND_INTERVAL,  // ActivityManager.PROCESS_STATE_BACKUP
         PSS_FIRST_BACKGROUND_INTERVAL,  // ActivityManager.PROCESS_STATE_HEAVY_WEIGHT
         PSS_FIRST_BACKGROUND_INTERVAL,  // ActivityManager.PROCESS_STATE_SERVICE
@@ -522,6 +527,7 @@
         PSS_SAME_IMPORTANT_INTERVAL,    // ActivityManager.PROCESS_STATE_TOP_SLEEPING
         PSS_SAME_IMPORTANT_INTERVAL,    // ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND
         PSS_SAME_IMPORTANT_INTERVAL,    // ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND
+        PSS_SAME_IMPORTANT_INTERVAL,    // ActivityManager.PROCESS_STATE_TRANSIENT_BACKGROUND
         PSS_SAME_IMPORTANT_INTERVAL,    // ActivityManager.PROCESS_STATE_BACKUP
         PSS_SAME_IMPORTANT_INTERVAL,    // ActivityManager.PROCESS_STATE_HEAVY_WEIGHT
         PSS_SAME_SERVICE_INTERVAL,      // ActivityManager.PROCESS_STATE_SERVICE
@@ -542,6 +548,7 @@
         PSS_FIRST_BACKGROUND_INTERVAL,      // ActivityManager.PROCESS_STATE_TOP_SLEEPING
         PSS_TEST_FIRST_BACKGROUND_INTERVAL, // ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND
         PSS_TEST_FIRST_BACKGROUND_INTERVAL, // ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND
+        PSS_TEST_FIRST_BACKGROUND_INTERVAL, // ActivityManager.PROCESS_STATE_TRANSIENT_BACKGROUND
         PSS_TEST_FIRST_BACKGROUND_INTERVAL, // ActivityManager.PROCESS_STATE_BACKUP
         PSS_TEST_FIRST_BACKGROUND_INTERVAL, // ActivityManager.PROCESS_STATE_HEAVY_WEIGHT
         PSS_TEST_FIRST_BACKGROUND_INTERVAL, // ActivityManager.PROCESS_STATE_SERVICE
@@ -562,6 +569,7 @@
         PSS_TEST_SAME_IMPORTANT_INTERVAL,   // ActivityManager.PROCESS_STATE_TOP_SLEEPING
         PSS_TEST_SAME_IMPORTANT_INTERVAL,   // ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND
         PSS_TEST_SAME_IMPORTANT_INTERVAL,   // ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND
+        PSS_TEST_SAME_IMPORTANT_INTERVAL,   // ActivityManager.PROCESS_STATE_TRANSIENT_BACKGROUND
         PSS_TEST_SAME_IMPORTANT_INTERVAL,   // ActivityManager.PROCESS_STATE_BACKUP
         PSS_TEST_SAME_IMPORTANT_INTERVAL,   // ActivityManager.PROCESS_STATE_HEAVY_WEIGHT
         PSS_TEST_SAME_BACKGROUND_INTERVAL,  // ActivityManager.PROCESS_STATE_SERVICE
diff --git a/services/core/java/com/android/server/job/JobSchedulerService.java b/services/core/java/com/android/server/job/JobSchedulerService.java
index abb2b55..e2c1274 100644
--- a/services/core/java/com/android/server/job/JobSchedulerService.java
+++ b/services/core/java/com/android/server/job/JobSchedulerService.java
@@ -1916,7 +1916,8 @@
         }
 
         try {
-            final int uid = AppGlobals.getPackageManager().getPackageUid(pkgName, 0, userId);
+            final int uid = AppGlobals.getPackageManager().getPackageUid(pkgName, 0,
+                    userId != UserHandle.USER_ALL ? userId : UserHandle.USER_SYSTEM);
             if (uid < 0) {
                 return JobSchedulerShellCommand.CMD_ERR_NO_PACKAGE;
             }
@@ -1942,6 +1943,25 @@
         return 0;
     }
 
+    // Shell command infrastructure: immediately timeout currently executing jobs
+    int executeTimeoutCommand(PrintWriter pw, String pkgName, int userId,
+            boolean hasJobId, int jobId) {
+        if (DEBUG) {
+            Slog.v(TAG, "executeTimeoutCommand(): " + pkgName + "/" + userId + " " + jobId);
+        }
+
+        synchronized (mLock) {
+            boolean foundSome = false;
+            for (int i=0; i<mActiveServices.size(); i++) {
+                mActiveServices.get(i).timeoutIfExecutingLocked(pkgName, userId, hasJobId, jobId);
+            }
+            if (!foundSome) {
+                pw.println("No matching executing jobs found.");
+            }
+        }
+        return 0;
+    }
+
     void setMonitorBattery(boolean enabled) {
         synchronized (mLock) {
             if (mBatteryController != null) {
diff --git a/services/core/java/com/android/server/job/JobSchedulerShellCommand.java b/services/core/java/com/android/server/job/JobSchedulerShellCommand.java
index 1c31c3e..fdfb345 100644
--- a/services/core/java/com/android/server/job/JobSchedulerShellCommand.java
+++ b/services/core/java/com/android/server/job/JobSchedulerShellCommand.java
@@ -16,11 +16,11 @@
 
 package com.android.server.job;
 
+import android.app.ActivityManager;
 import android.app.AppGlobals;
 import android.content.pm.IPackageManager;
 import android.content.pm.PackageManager;
 import android.os.Binder;
-import android.os.RemoteException;
 import android.os.ShellCommand;
 import android.os.UserHandle;
 
@@ -46,18 +46,20 @@
             switch (cmd != null ? cmd : "") {
                 case "run":
                     return runJob(pw);
+                case "timeout":
+                    return timeout(pw);
                 case "monitor-battery":
-                    return runMonitorBattery(pw);
+                    return monitorBattery(pw);
                 case "get-battery-seq":
-                    return runGetBatterySeq(pw);
+                    return getBatterySeq(pw);
                 case "get-battery-charging":
-                    return runGetBatteryCharging(pw);
+                    return getBatteryCharging(pw);
                 case "get-battery-not-low":
-                    return runGetBatteryNotLow(pw);
+                    return getBatteryNotLow(pw);
                 case "get-storage-seq":
-                    return runGetStorageSeq(pw);
+                    return getStorageSeq(pw);
                 case "get-storage-not-low":
-                    return runGetStorageNotLow(pw);
+                    return getStorageNotLow(pw);
                 default:
                     return handleDefaultCommands(cmd);
             }
@@ -154,7 +156,42 @@
         }
     }
 
-    private int runMonitorBattery(PrintWriter pw) throws Exception {
+    private int timeout(PrintWriter pw) throws Exception {
+        checkPermission("force timeout jobs");
+
+        int userId = UserHandle.USER_ALL;
+
+        String opt;
+        while ((opt = getNextOption()) != null) {
+            switch (opt) {
+                case "-u":
+                case "--user":
+                    userId = UserHandle.parseUserArg(getNextArgRequired());
+                    break;
+
+                default:
+                    pw.println("Error: unknown option '" + opt + "'");
+                    return -1;
+            }
+        }
+
+        if (userId == UserHandle.USER_CURRENT) {
+            userId = ActivityManager.getCurrentUser();
+        }
+
+        final String pkgName = getNextArg();
+        final String jobIdStr = getNextArg();
+        final int jobId = jobIdStr != null ? Integer.parseInt(jobIdStr) : -1;
+
+        final long ident = Binder.clearCallingIdentity();
+        try {
+            return mInternal.executeTimeoutCommand(pw, pkgName, userId, jobIdStr != null, jobId);
+        } finally {
+            Binder.restoreCallingIdentity(ident);
+        }
+    }
+
+    private int monitorBattery(PrintWriter pw) throws Exception {
         checkPermission("change battery monitoring");
         String opt = getNextArgRequired();
         boolean enabled;
@@ -166,37 +203,42 @@
             getErrPrintWriter().println("Error: unknown option " + opt);
             return 1;
         }
-        mInternal.setMonitorBattery(enabled);
-        if (enabled) pw.println("Battery monitoring enabled");
-        else pw.println("Battery monitoring disabled");
+        final long ident = Binder.clearCallingIdentity();
+        try {
+            mInternal.setMonitorBattery(enabled);
+            if (enabled) pw.println("Battery monitoring enabled");
+            else pw.println("Battery monitoring disabled");
+        } finally {
+            Binder.restoreCallingIdentity(ident);
+        }
         return 0;
     }
 
-    private int runGetBatterySeq(PrintWriter pw) {
+    private int getBatterySeq(PrintWriter pw) {
         int seq = mInternal.getBatterySeq();
         pw.println(seq);
         return 0;
     }
 
-    private int runGetBatteryCharging(PrintWriter pw) {
+    private int getBatteryCharging(PrintWriter pw) {
         boolean val = mInternal.getBatteryCharging();
         pw.println(val);
         return 0;
     }
 
-    private int runGetBatteryNotLow(PrintWriter pw) {
+    private int getBatteryNotLow(PrintWriter pw) {
         boolean val = mInternal.getBatteryNotLow();
         pw.println(val);
         return 0;
     }
 
-    private int runGetStorageSeq(PrintWriter pw) {
+    private int getStorageSeq(PrintWriter pw) {
         int seq = mInternal.getStorageSeq();
         pw.println(seq);
         return 0;
     }
 
-    private int runGetStorageNotLow(PrintWriter pw) {
+    private int getStorageNotLow(PrintWriter pw) {
         boolean val = mInternal.getStorageNotLow();
         pw.println(val);
         return 0;
@@ -216,6 +258,12 @@
         pw.println("         connectivity are not currently met");
         pw.println("      -u or --user: specify which user's job is to be run; the default is");
         pw.println("         the primary or system user");
+        pw.println("  timeout [-u | --user USER_ID] [PACKAGE] [JOB_ID]");
+        pw.println("    Trigger immediate timeout of currently executing jobs, as if their.");
+        pw.println("    execution timeout had expired.");
+        pw.println("    Options:");
+        pw.println("      -u or --user: specify which user's job is to be run; the default is");
+        pw.println("         all users");
         pw.println("  monitor-battery [on|off]");
         pw.println("    Control monitoring of all battery changes.  Off by default.  Turning");
         pw.println("    on makes get-battery-seq useful.");
diff --git a/services/core/java/com/android/server/job/JobServiceContext.java b/services/core/java/com/android/server/job/JobServiceContext.java
index 9144966..73beecf 100644
--- a/services/core/java/com/android/server/job/JobServiceContext.java
+++ b/services/core/java/com/android/server/job/JobServiceContext.java
@@ -184,7 +184,8 @@
             scheduleOpTimeOutLocked();
             final Intent intent = new Intent().setComponent(job.getServiceComponent());
             boolean binding = mContext.bindServiceAsUser(intent, this,
-                    Context.BIND_AUTO_CREATE | Context.BIND_NOT_FOREGROUND,
+                    Context.BIND_AUTO_CREATE | Context.BIND_NOT_FOREGROUND
+                            | Context.BIND_IMPORTANT_BACKGROUND,
                     new UserHandle(job.getUserId()));
             if (!binding) {
                 if (DEBUG) {
@@ -255,6 +256,20 @@
         return mTimeoutElapsed;
     }
 
+    boolean timeoutIfExecutingLocked(String pkgName, int userId, boolean matchJobId, int jobId) {
+        final JobStatus executing = getRunningJob();
+        if (executing != null && (userId == UserHandle.USER_ALL || userId == executing.getUserId())
+                && (pkgName == null || pkgName.equals(executing.getSourcePackageName()))
+                && (!matchJobId || jobId == executing.getJobId())) {
+            if (mVerb == VERB_EXECUTING) {
+                mParams.setStopReason(JobParameters.REASON_TIMEOUT);
+                sendStopMessageLocked();
+                return true;
+            }
+        }
+        return false;
+    }
+
     @Override
     public void jobFinished(int jobId, boolean reschedule) {
         doCallback(reschedule);