diff options
24 files changed, 1065 insertions, 141 deletions
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java index ac1d19e81eb4..66d221aefc14 100644 --- a/core/java/android/app/ActivityManager.java +++ b/core/java/android/app/ActivityManager.java @@ -458,42 +458,45 @@ public class ActivityManager { /** @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 @@ public class ActivityManager { /** @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. */ @@ -3249,7 +3252,7 @@ public class ActivityManager { 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; @@ -3306,7 +3309,7 @@ public class ActivityManager { } 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 c03883cf9b03..a8214fac26a2 100644 --- a/core/java/android/content/Context.java +++ b/core/java/android/content/Context.java @@ -323,6 +323,12 @@ public abstract class Context { 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 54f4b0342203..ea5892547969 100755 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -724,6 +724,19 @@ public final class Settings { "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. @@ -9002,13 +9015,30 @@ public final class Settings { * 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 8c2c2362f994..94706687f6de 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 @@ public final class ProcessState { 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 ef20750cdb19..fef85da27f17 100644 --- a/core/java/com/android/internal/notification/SystemNotificationChannels.java +++ b/core/java/com/android/internal/notification/SystemNotificationChannels.java @@ -45,6 +45,7 @@ public class SystemNotificationChannels { 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 @@ public class SystemNotificationChannels { 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 35b12ffb5d68..e633d66514cc 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 59505b7a2bae..bd70ca8c2191 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -2979,6 +2979,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 1634b8818c98..c2f1a5abe647 100644 --- a/packages/SystemUI/AndroidManifest.xml +++ b/packages/SystemUI/AndroidManifest.xml @@ -544,6 +544,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 000000000000..0a1dea05413f --- /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 000000000000..b5434b2402aa --- /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 8e9847575485..1ea4f835073b 100644 --- a/packages/SystemUI/res/values/strings.xml +++ b/packages/SystemUI/res/values/strings.xml @@ -2033,4 +2033,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 000000000000..086e5e52e037 --- /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 87f1cdb38a93..f9b4372b36c6 100644 --- a/proto/src/metrics_constants.proto +++ b/proto/src/metrics_constants.proto @@ -3952,6 +3952,11 @@ message MetricsEvent { // 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 ---- // OPEN: Settings > System > Languages & input > Advanced > Lift to open camera diff --git a/proto/src/system_messages.proto b/proto/src/system_messages.proto index 65cc17eec6bd..53b3fe9c1a0d 100644 --- a/proto/src/system_messages.proto +++ b/proto/src/system_messages.proto @@ -176,6 +176,10 @@ message SystemMessage { // 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 9d3d5313eb4a..e1756d1bf198 100644 --- a/services/core/java/com/android/server/DropBoxManagerService.java +++ b/services/core/java/com/android/server/DropBoxManagerService.java @@ -371,6 +371,14 @@ public final class DropBoxManagerService extends SystemService { 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 8ad3d23648bf..20a6d14e5ca4 100644 --- a/services/core/java/com/android/server/InputMethodManagerService.java +++ b/services/core/java/com/android/server/InputMethodManagerService.java @@ -212,6 +212,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub 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 d008c5e0ccb6..5edf19a9d012 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 java.util.Set; 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.Looper; 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 @@ public final class ActiveServices { // 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 @@ public final class ActiveServices { /** 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 @@ public final class ActiveServices { }; /** + * 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 @@ public final class ActiveServices { 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 @@ public final class ActiveServices { rescheduleDelayedStartsLocked(); } } break; + case MSG_UPDATE_FOREGROUND_APPS: { + updateForegroundApps(this); + } break; } } @@ -528,7 +534,7 @@ public final class ActiveServices { 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 @@ public final class ActiveServices { } } + 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 @@ public final class ActiveServices { } 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 @@ public final class ActiveServices { 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 @@ public final class ActiveServices { 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 @@ public final class ActiveServices { 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 @@ public final class ActiveServices { 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 @@ public final class ActiveServices { } cancelForegroundNotificationLocked(r); + if (r.isForeground) { + decActiveForegroundAppLocked(smap, r); + } r.isForeground = false; r.foregroundId = 0; r.foregroundNoti = null; @@ -2612,6 +2805,22 @@ public final class ActiveServices { 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 @@ public final class ActiveServices { } } + 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 55ee18335410..5749f31ddb2e 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.content.ContentResolver; 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 @@ final class ActivityManagerConstants extends ContentObserver { } 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 @@ final class ActivityManagerConstants extends ContentObserver { 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 6b97481b3bc9..ace2b557c4a6 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 @@ public class ActivityManagerService extends IActivityManager.Stub // 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 @@ public class ActivityManagerService extends IActivityManager.Stub // 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; @@ -2127,7 +2086,7 @@ public class ActivityManagerService extends IActivityManager.Stub 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: { @@ -4239,7 +4198,7 @@ public class ActivityManagerService extends IActivityManager.Stub "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"); } @@ -5325,7 +5284,7 @@ public class ActivityManagerService extends IActivityManager.Stub 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. @@ -7083,7 +7042,7 @@ public class ActivityManagerService extends IActivityManager.Stub 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"); @@ -12257,14 +12216,15 @@ public class ActivityManagerService extends IActivityManager.Stub } 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(); @@ -12278,7 +12238,20 @@ public class ActivityManagerService extends IActivityManager.Stub 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; } } @@ -19009,6 +18982,8 @@ public class ActivityManagerService extends IActivityManager.Stub removeTasksByPackageNameLocked(ssp, userId); + mServices.removeUninstalledPackageLocked(ssp, userId); + // Hide the "unsupported display" dialog if necessary. if (mUnsupportedDisplaySizeDialog != null && ssp.equals( mUnsupportedDisplaySizeDialog.getPackageName())) { @@ -20798,8 +20773,8 @@ public class ActivityManagerService extends IActivityManager.Stub 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; @@ -20831,7 +20806,7 @@ public class ActivityManagerService extends IActivityManager.Stub 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. @@ -20896,8 +20871,7 @@ public class ActivityManagerService extends IActivityManager.Stub 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 @@ -20943,7 +20917,8 @@ public class ActivityManagerService extends IActivityManager.Stub 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. @@ -20987,6 +20962,12 @@ public class ActivityManagerService extends IActivityManager.Stub } } } + } 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) { @@ -21125,7 +21106,8 @@ public class ActivityManagerService extends IActivityManager.Stub } } - 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; @@ -21147,6 +21129,7 @@ public class ActivityManagerService extends IActivityManager.Stub 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. @@ -21342,7 +21325,8 @@ public class ActivityManagerService extends IActivityManager.Stub 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; } } @@ -21424,7 +21408,7 @@ public class ActivityManagerService extends IActivityManager.Stub 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. @@ -21467,10 +21451,10 @@ public class ActivityManagerService extends IActivityManager.Stub 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); } @@ -21503,7 +21487,7 @@ public class ActivityManagerService extends IActivityManager.Stub */ 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)) { @@ -21533,10 +21517,10 @@ public class ActivityManagerService extends IActivityManager.Stub 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(); @@ -21794,7 +21778,7 @@ public class ActivityManagerService extends IActivityManager.Stub 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); @@ -21967,7 +21951,8 @@ public class ActivityManagerService extends IActivityManager.Stub 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 @@ -21976,8 +21961,8 @@ public class ActivityManagerService extends IActivityManager.Stub && 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) { @@ -22493,7 +22478,8 @@ public class ActivityManagerService extends IActivityManager.Stub // 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 { @@ -22598,7 +22584,7 @@ public class ActivityManagerService extends IActivityManager.Stub 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(); @@ -22623,7 +22609,7 @@ public class ActivityManagerService extends IActivityManager.Stub 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 cd370412554e..9b7a0c43b191 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 @@ final class ConnectionRecord { 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 0dc678813338..80e7c757931c 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 @@ final class ProcessList { 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 @@ final class ProcessList { 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 @@ final class ProcessList { 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 @@ final class ProcessList { 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 @@ final class ProcessList { 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 @@ final class ProcessList { 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 abb2b555be57..e2c1274a4be6 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 @@ public final class JobSchedulerService extends com.android.server.SystemService } 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 @@ public final class JobSchedulerService extends com.android.server.SystemService 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 1c31c3e6af96..fdfb345b3fb2 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 @@ public class JobSchedulerShellCommand extends ShellCommand { 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 @@ public class JobSchedulerShellCommand extends ShellCommand { } } - 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 @@ public class JobSchedulerShellCommand extends ShellCommand { 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 @@ public class JobSchedulerShellCommand extends ShellCommand { 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 9144966da409..73beecfdd711 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 @@ public class JobServiceContext extends IJobCallback.Stub implements ServiceConne 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 @@ public class JobServiceContext extends IJobCallback.Stub implements ServiceConne 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); |