From fe0e09e4e384ec26a4a6f5ffba1f6e60dae2a7f4 Mon Sep 17 00:00:00 2001 From: Vishnu Nair Date: Tue, 4 Sep 2018 19:49:57 -0700 Subject: DO NOT MERGE: Reset launch start times when removing a process When removing an exiting process that is running foreground activities, clear the launch times for the current windowing mode. When an app process is removed, activities from the process may be relaunched. In the case of forceStopPackageLocked the activities are finished before any window is drawn, and the launch time is not cleared. This will be incorrectly used to calculate launch time for the next launched activity launched in the same windowing mode. Bug: 80084651 Test: adb shell am start -W com.amazon.mShop.android.shopping/com.amazon.mShop.home.HomeActivity && sleep 1 && adb shell am force-stop com.amazon.mShop.android.shopping Change-Id: I2c4f0716c922baa1ad209b4ea1fa7ce366e0e108 (cherry picked from commit 9372683dd2b6ceafee4714770b51e67066e3d8bc) --- .../java/com/android/server/am/ActivityManagerService.java | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index c5b8b950d456..2f1021a3dd9b 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -5889,6 +5889,7 @@ public class ActivityManagerService extends IActivityManager.Stub private final void handleAppDiedLocked(ProcessRecord app, boolean restarting, boolean allowRestart) { int pid = app.pid; + final boolean clearLaunchStartTime = !restarting && app.removed && app.foregroundActivities; boolean kept = cleanUpApplicationRecordLocked(app, restarting, allowRestart, -1, false /*replacingPid*/); if (!kept && !restarting) { @@ -5929,6 +5930,19 @@ public class ActivityManagerService extends IActivityManager.Stub } finally { mWindowManager.continueSurfaceLayout(); } + + // Hack for pi + // When an app process is removed, activities from the process may be relaunched. In the + // case of forceStopPackageLocked the activities are finished before any window is drawn, + // and the launch time is not cleared. This will be incorrectly used to calculate launch + // time for the next launched activity launched in the same windowing mode. + if (clearLaunchStartTime) { + final LaunchTimeTracker.Entry entry = mStackSupervisor + .getLaunchTimeTracker().getEntry(mStackSupervisor.getWindowingMode()); + if (entry != null) { + entry.mLaunchStartTime = 0; + } + } } private final int getLRURecordIndexForAppLocked(IApplicationThread thread) { -- cgit v1.2.3-59-g8ed1b From 553bb7c6a2b2c70b1cd011aec9bf9c151818d8c3 Mon Sep 17 00:00:00 2001 From: Amith Yamasani Date: Wed, 5 Sep 2018 18:52:35 -0700 Subject: Keep app in high memory adjust if moving from TOP to FGS If an app was in the TOP state and immediately moved to a foreground service state, then try harder to keep it in memory for another 20 seconds before releasing the memory to bound foreground services. Using an oom_adj value of 50 which is between "fore" and "vis". So BFGS apps might get killed ("vis") before this recently FGS'ed app. That way any app that has a lot of state in memory that it needs to persist before getting killed has a chance to do so. Also bind NotificationListeners with a special bind flag to rank them below FGS (perceptible adj) so that they can be killed before any other foreground services or bound services get killed. Bug: 110969183 Test: Manual for now. Take a bunch of portrait pictures and hit home, while being under memory pressure with a bunch of notification listeners. Change-Id: Ie8934c2331afe6450c582b209869aeca7272f58a Merged-In: Ie8934c2331afe6450c582b209869aeca7272f58a (cherry picked from commit b735830a1e71e72c4e72260d7eab0382b4ee19df) --- core/java/android/content/Context.java | 9 ++++++++ .../server/am/ActivityManagerConstants.java | 11 ++++++++- .../android/server/am/ActivityManagerService.java | 26 ++++++++++++++++++++++ .../java/com/android/server/am/ProcessList.java | 5 +++++ .../java/com/android/server/am/ProcessRecord.java | 6 +++++ .../server/notification/ManagedServices.java | 10 ++++++--- .../notification/NotificationManagerService.java | 14 ++++++++++++ 7 files changed, 77 insertions(+), 4 deletions(-) diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java index 90a94ee76085..b53202ef1741 100644 --- a/core/java/android/content/Context.java +++ b/core/java/android/content/Context.java @@ -325,6 +325,15 @@ public abstract class Context { */ public static final int BIND_ADJUST_WITH_ACTIVITY = 0x0080; + /** + * Flag for {@link #bindService}: If binding from something better than perceptible, + * still set the adjust below perceptible. This would be used for bound services that can + * afford to be evicted when under extreme memory pressure, but should be restarted as soon + * as possible. + * @hide + */ + public static final int BIND_ADJUST_BELOW_PERCEPTIBLE = 0x0100; + /** * @hide Flag for {@link #bindService}: allows binding to a service provided * by an instant app. Note that the caller may not have access to the instant diff --git a/services/core/java/com/android/server/am/ActivityManagerConstants.java b/services/core/java/com/android/server/am/ActivityManagerConstants.java index 9bf72fb86cd6..d14c1a1adf77 100644 --- a/services/core/java/com/android/server/am/ActivityManagerConstants.java +++ b/services/core/java/com/android/server/am/ActivityManagerConstants.java @@ -67,6 +67,7 @@ final class ActivityManagerConstants extends ContentObserver { static final String KEY_BOUND_SERVICE_CRASH_RESTART_DURATION = "service_crash_restart_duration"; static final String KEY_BOUND_SERVICE_CRASH_MAX_RETRY = "service_crash_max_retry"; static final String KEY_PROCESS_START_ASYNC = "process_start_async"; + static final String KEY_TOP_TO_FGS_GRACE_DURATION = "top_to_fgs_grace_duration"; private static final int DEFAULT_MAX_CACHED_PROCESSES = 32; private static final long DEFAULT_BACKGROUND_SETTLE_TIME = 60*1000; @@ -95,7 +96,7 @@ final class ActivityManagerConstants extends ContentObserver { private static final long DEFAULT_BOUND_SERVICE_CRASH_RESTART_DURATION = 30*60_000; private static final int DEFAULT_BOUND_SERVICE_CRASH_MAX_RETRY = 16; private static final boolean DEFAULT_PROCESS_START_ASYNC = true; - + private static final long DEFAULT_TOP_TO_FGS_GRACE_DURATION = 15 * 1000; // Maximum number of cached processes we will allow. public int MAX_CACHED_PROCESSES = DEFAULT_MAX_CACHED_PROCESSES; @@ -207,6 +208,10 @@ final class ActivityManagerConstants extends ContentObserver { // Indicates if the processes need to be started asynchronously. public boolean FLAG_PROCESS_START_ASYNC = DEFAULT_PROCESS_START_ASYNC; + // Allow app just moving from TOP to FOREGROUND_SERVICE to stay in a higher adj value for + // this long. + public long TOP_TO_FGS_GRACE_DURATION = DEFAULT_TOP_TO_FGS_GRACE_DURATION; + // Indicates whether the activity starts logging is enabled. // Controlled by Settings.Global.ACTIVITY_STARTS_LOGGING_ENABLED boolean mFlagActivityStartsLoggingEnabled; @@ -348,6 +353,8 @@ final class ActivityManagerConstants extends ContentObserver { DEFAULT_BOUND_SERVICE_CRASH_MAX_RETRY); FLAG_PROCESS_START_ASYNC = mParser.getBoolean(KEY_PROCESS_START_ASYNC, DEFAULT_PROCESS_START_ASYNC); + TOP_TO_FGS_GRACE_DURATION = mParser.getDurationMillis(KEY_TOP_TO_FGS_GRACE_DURATION, + DEFAULT_TOP_TO_FGS_GRACE_DURATION); updateMaxCachedProcesses(); } @@ -423,6 +430,8 @@ final class ActivityManagerConstants extends ContentObserver { pw.println(MAX_SERVICE_INACTIVITY); pw.print(" "); pw.print(KEY_BG_START_TIMEOUT); pw.print("="); pw.println(BG_START_TIMEOUT); + pw.print(" "); pw.print(KEY_TOP_TO_FGS_GRACE_DURATION); pw.print("="); + pw.println(TOP_TO_FGS_GRACE_DURATION); 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 2f1021a3dd9b..145c1c964a31 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -23390,6 +23390,19 @@ public class ActivityManagerService extends IActivityManager.Stub } } + // If the app was recently in the foreground and moved to a foreground service status, + // allow it to get a higher rank in memory for some time, compared to other foreground + // services so that it can finish performing any persistence/processing of in-memory state. + if (app.foregroundServices && adj > ProcessList.PERCEPTIBLE_RECENT_FOREGROUND_APP_ADJ + && (app.lastTopTime + mConstants.TOP_TO_FGS_GRACE_DURATION > now + || app.setProcState <= ActivityManager.PROCESS_STATE_TOP)) { + adj = ProcessList.PERCEPTIBLE_RECENT_FOREGROUND_APP_ADJ; + app.adjType = "fg-service-act"; + if (DEBUG_OOM_ADJ_REASON || logUid == appUid) { + reportOomAdjMessageLocked(TAG_OOM_ADJ, "Raise to recent fg: " + app); + } + } + if (adj > ProcessList.PERCEPTIBLE_APP_ADJ || procState > ActivityManager.PROCESS_STATE_TRANSIENT_BACKGROUND) { if (app.forcingToImportant != null) { @@ -23654,6 +23667,10 @@ public class ActivityManagerService extends IActivityManager.Stub schedGroup = ProcessList.SCHED_GROUP_DEFAULT; procState = ActivityManager.PROCESS_STATE_PERSISTENT; } + } else if ((cr.flags & Context.BIND_ADJUST_BELOW_PERCEPTIBLE) != 0 + && clientAdj < ProcessList.PERCEPTIBLE_APP_ADJ + && adj > ProcessList.PERCEPTIBLE_APP_ADJ + 1) { + newAdj = ProcessList.PERCEPTIBLE_APP_ADJ + 1; } else if ((cr.flags&Context.BIND_NOT_VISIBLE) != 0 && clientAdj < ProcessList.PERCEPTIBLE_APP_ADJ && adj > ProcessList.PERCEPTIBLE_APP_ADJ) { @@ -24624,6 +24641,8 @@ public class ActivityManagerService extends IActivityManager.Stub // Must be called before updating setProcState maybeUpdateUsageStatsLocked(app, nowElapsed); + maybeUpdateLastTopTime(app, now); + app.setProcState = app.curProcState; if (app.setProcState >= ActivityManager.PROCESS_STATE_HOME) { app.notCachedSinceIdle = false; @@ -24848,6 +24867,13 @@ public class ActivityManagerService extends IActivityManager.Stub } } + private void maybeUpdateLastTopTime(ProcessRecord app, long nowUptime) { + if (app.setProcState <= ActivityManager.PROCESS_STATE_TOP + && app.curProcState > ActivityManager.PROCESS_STATE_TOP) { + app.lastTopTime = nowUptime; + } + } + private final void setProcessTrackerStateLocked(ProcessRecord proc, int memFactor, long now) { if (proc.thread != null) { if (proc.baseProcessTracker != null) { diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java index 784d62e51966..3ac7885eba37 100644 --- a/services/core/java/com/android/server/am/ProcessList.java +++ b/services/core/java/com/android/server/am/ProcessList.java @@ -104,6 +104,11 @@ public final class ProcessList { static final int VISIBLE_APP_ADJ = 100; static final int VISIBLE_APP_LAYER_MAX = PERCEPTIBLE_APP_ADJ - VISIBLE_APP_ADJ - 1; + // This is a process that was recently TOP and moved to FGS. Continue to treat it almost + // like a foreground app for a while. + // @see TOP_TO_FGS_GRACE_PERIOD + static final int PERCEPTIBLE_RECENT_FOREGROUND_APP_ADJ = 50; + // This is the process running the current foreground app. We'd really // rather not kill it! static final int FOREGROUND_APP_ADJ = 0; diff --git a/services/core/java/com/android/server/am/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java index 28ebbb87f261..e3e839f63172 100644 --- a/services/core/java/com/android/server/am/ProcessRecord.java +++ b/services/core/java/com/android/server/am/ProcessRecord.java @@ -163,6 +163,7 @@ final class ProcessRecord { long lastRequestedGc; // When we last asked the app to do a gc long lastLowMemory; // When we last told the app that memory is low long lastProviderTime; // The last time someone else was using a provider in this process. + long lastTopTime; // The last time the process was in the TOP state or greater. boolean reportLowMemory; // Set to true when waiting to report low mem boolean empty; // Is this an empty background process? boolean cached; // Is this a cached process? @@ -380,6 +381,11 @@ final class ProcessRecord { TimeUtils.formatDuration(lastProviderTime, nowUptime, pw); pw.println(); } + if (lastTopTime > 0) { + pw.print(prefix); pw.print("lastTopTime="); + TimeUtils.formatDuration(lastTopTime, nowUptime, pw); + pw.println(); + } if (hasStartedServices) { pw.print(prefix); pw.print("hasStartedServices="); pw.println(hasStartedServices); } diff --git a/services/core/java/com/android/server/notification/ManagedServices.java b/services/core/java/com/android/server/notification/ManagedServices.java index f7becd518861..30fa7fe4ce87 100644 --- a/services/core/java/com/android/server/notification/ManagedServices.java +++ b/services/core/java/com/android/server/notification/ManagedServices.java @@ -175,6 +175,10 @@ abstract public class ManagedServices { } } + protected int getBindFlags() { + return BIND_AUTO_CREATE | BIND_FOREGROUND_SERVICE | BIND_ALLOW_WHITELIST_MANAGEMENT; + } + protected void onServiceRemovedLocked(ManagedServiceInfo removed) { } private ManagedServiceInfo newServiceInfo(IInterface service, @@ -1022,9 +1026,9 @@ abstract public class ManagedServices { } }; if (!mContext.bindServiceAsUser(intent, - serviceConnection, - BIND_AUTO_CREATE | BIND_FOREGROUND_SERVICE | BIND_ALLOW_WHITELIST_MANAGEMENT, - new UserHandle(userid))) { + serviceConnection, + getBindFlags(), + new UserHandle(userid))) { mServicesBinding.remove(servicesBindingTag); Slog.w(TAG, "Unable to bind " + getCaption() + " service: " + intent); return; diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java index 8304e2691979..f2b7bbe636e5 100644 --- a/services/core/java/com/android/server/notification/NotificationManagerService.java +++ b/services/core/java/com/android/server/notification/NotificationManagerService.java @@ -33,6 +33,10 @@ import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_PEEK; import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_SCREEN_OFF; import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_SCREEN_ON; import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_STATUS_BAR; +import static android.content.Context.BIND_ADJUST_BELOW_PERCEPTIBLE; +import static android.content.Context.BIND_ALLOW_WHITELIST_MANAGEMENT; +import static android.content.Context.BIND_AUTO_CREATE; +import static android.content.Context.BIND_FOREGROUND_SERVICE; import static android.content.pm.PackageManager.FEATURE_LEANBACK; import static android.content.pm.PackageManager.FEATURE_TELEVISION; import static android.content.pm.PackageManager.PERMISSION_GRANTED; @@ -6520,6 +6524,16 @@ public class NotificationManagerService extends SystemService { } + @Override + protected int getBindFlags() { + // Most of the same flags as the base, but also add BIND_ADJUST_BELOW_PERCEPTIBLE + // because too many 3P apps could be kept in memory as notification listeners and + // cause extreme memory pressure. + // TODO: Change the binding lifecycle of NotificationListeners to avoid this situation. + return BIND_AUTO_CREATE | BIND_FOREGROUND_SERVICE + | BIND_ADJUST_BELOW_PERCEPTIBLE | BIND_ALLOW_WHITELIST_MANAGEMENT; + } + @Override protected Config getConfig() { Config c = new Config(); -- cgit v1.2.3-59-g8ed1b From 35f31cbac405b20ec1cd55714609c88f98a99c14 Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Mon, 24 Sep 2018 13:23:57 -0600 Subject: Recover shady content:// paths. The path-permission element offers prefix or regex style matching of paths, but most providers internally use UriMatcher to decide what to do with an incoming Uri. This causes trouble because UriMatcher uses Uri.getPathSegments(), which quietly ignores "empty" paths. Consider this example: uriMatcher.addURI("com.example", "/private", CODE_PRIVATE); content://com.example//private The Uri above will pass the security check, since it's not technically a prefix match. But the UriMatcher will then match it as CODE_PRIVATE, since it ignores the "//" zero-length path. Since we can't safely change the behavior of either path-permission or UriMatcher, we're left with recovering these shady paths by trimming away zero-length paths. Bug: 112555574 Test: atest android.appsecurity.cts.AppSecurityTests Test: atest FrameworksCoreTests:android.content.ContentProviderTest Merged-In: Ibadbfa4fc904ec54780c8102958735b03293fb9a Change-Id: Ibadbfa4fc904ec54780c8102958735b03293fb9a (cherry picked from commit c084ddbf826b25808c4553e4b5992c6723eac4ea) --- core/java/android/content/ContentProvider.java | 53 ++++++++++++++-------- .../android/content/ContentProviderOperation.java | 16 +------ 2 files changed, 36 insertions(+), 33 deletions(-) diff --git a/core/java/android/content/ContentProvider.java b/core/java/android/content/ContentProvider.java index cdeaea3ebcae..e2c898d153ee 100644 --- a/core/java/android/content/ContentProvider.java +++ b/core/java/android/content/ContentProvider.java @@ -54,6 +54,7 @@ import java.io.IOException; import java.io.PrintWriter; import java.util.ArrayList; import java.util.Arrays; +import java.util.Objects; /** * Content providers are one of the primary building blocks of Android applications, providing @@ -208,7 +209,7 @@ public abstract class ContentProvider implements ComponentCallbacks2 { @Override public Cursor query(String callingPkg, Uri uri, @Nullable String[] projection, @Nullable Bundle queryArgs, @Nullable ICancellationSignal cancellationSignal) { - validateIncomingUri(uri); + uri = validateIncomingUri(uri); uri = maybeGetUriWithoutUserId(uri); if (enforceReadPermission(callingPkg, uri, null) != AppOpsManager.MODE_ALLOWED) { // The caller has no access to the data, so return an empty cursor with @@ -247,14 +248,14 @@ public abstract class ContentProvider implements ComponentCallbacks2 { @Override public String getType(Uri uri) { - validateIncomingUri(uri); + uri = validateIncomingUri(uri); uri = maybeGetUriWithoutUserId(uri); return ContentProvider.this.getType(uri); } @Override public Uri insert(String callingPkg, Uri uri, ContentValues initialValues) { - validateIncomingUri(uri); + uri = validateIncomingUri(uri); int userId = getUserIdFromUri(uri); uri = maybeGetUriWithoutUserId(uri); if (enforceWritePermission(callingPkg, uri, null) != AppOpsManager.MODE_ALLOWED) { @@ -270,7 +271,7 @@ public abstract class ContentProvider implements ComponentCallbacks2 { @Override public int bulkInsert(String callingPkg, Uri uri, ContentValues[] initialValues) { - validateIncomingUri(uri); + uri = validateIncomingUri(uri); uri = maybeGetUriWithoutUserId(uri); if (enforceWritePermission(callingPkg, uri, null) != AppOpsManager.MODE_ALLOWED) { return 0; @@ -292,11 +293,12 @@ public abstract class ContentProvider implements ComponentCallbacks2 { for (int i = 0; i < numOperations; i++) { ContentProviderOperation operation = operations.get(i); Uri uri = operation.getUri(); - validateIncomingUri(uri); userIds[i] = getUserIdFromUri(uri); - if (userIds[i] != UserHandle.USER_CURRENT) { - // Removing the user id from the uri. - operation = new ContentProviderOperation(operation, true); + uri = validateIncomingUri(uri); + uri = maybeGetUriWithoutUserId(uri); + // Rebuild operation if we changed the Uri above + if (!Objects.equals(operation.getUri(), uri)) { + operation = new ContentProviderOperation(operation, uri); operations.set(i, operation); } if (operation.isReadOperation()) { @@ -331,7 +333,7 @@ public abstract class ContentProvider implements ComponentCallbacks2 { @Override public int delete(String callingPkg, Uri uri, String selection, String[] selectionArgs) { - validateIncomingUri(uri); + uri = validateIncomingUri(uri); uri = maybeGetUriWithoutUserId(uri); if (enforceWritePermission(callingPkg, uri, null) != AppOpsManager.MODE_ALLOWED) { return 0; @@ -347,7 +349,7 @@ public abstract class ContentProvider implements ComponentCallbacks2 { @Override public int update(String callingPkg, Uri uri, ContentValues values, String selection, String[] selectionArgs) { - validateIncomingUri(uri); + uri = validateIncomingUri(uri); uri = maybeGetUriWithoutUserId(uri); if (enforceWritePermission(callingPkg, uri, null) != AppOpsManager.MODE_ALLOWED) { return 0; @@ -364,7 +366,7 @@ public abstract class ContentProvider implements ComponentCallbacks2 { public ParcelFileDescriptor openFile( String callingPkg, Uri uri, String mode, ICancellationSignal cancellationSignal, IBinder callerToken) throws FileNotFoundException { - validateIncomingUri(uri); + uri = validateIncomingUri(uri); uri = maybeGetUriWithoutUserId(uri); enforceFilePermission(callingPkg, uri, mode, callerToken); final String original = setCallingPackage(callingPkg); @@ -380,7 +382,7 @@ public abstract class ContentProvider implements ComponentCallbacks2 { public AssetFileDescriptor openAssetFile( String callingPkg, Uri uri, String mode, ICancellationSignal cancellationSignal) throws FileNotFoundException { - validateIncomingUri(uri); + uri = validateIncomingUri(uri); uri = maybeGetUriWithoutUserId(uri); enforceFilePermission(callingPkg, uri, mode, null); final String original = setCallingPackage(callingPkg); @@ -406,7 +408,7 @@ public abstract class ContentProvider implements ComponentCallbacks2 { @Override public String[] getStreamTypes(Uri uri, String mimeTypeFilter) { - validateIncomingUri(uri); + uri = validateIncomingUri(uri); uri = maybeGetUriWithoutUserId(uri); return ContentProvider.this.getStreamTypes(uri, mimeTypeFilter); } @@ -415,7 +417,7 @@ public abstract class ContentProvider implements ComponentCallbacks2 { public AssetFileDescriptor openTypedAssetFile(String callingPkg, Uri uri, String mimeType, Bundle opts, ICancellationSignal cancellationSignal) throws FileNotFoundException { Bundle.setDefusable(opts, true); - validateIncomingUri(uri); + uri = validateIncomingUri(uri); uri = maybeGetUriWithoutUserId(uri); enforceFilePermission(callingPkg, uri, "r", null); final String original = setCallingPackage(callingPkg); @@ -434,7 +436,7 @@ public abstract class ContentProvider implements ComponentCallbacks2 { @Override public Uri canonicalize(String callingPkg, Uri uri) { - validateIncomingUri(uri); + uri = validateIncomingUri(uri); int userId = getUserIdFromUri(uri); uri = getUriWithoutUserId(uri); if (enforceReadPermission(callingPkg, uri, null) != AppOpsManager.MODE_ALLOWED) { @@ -450,7 +452,7 @@ public abstract class ContentProvider implements ComponentCallbacks2 { @Override public Uri uncanonicalize(String callingPkg, Uri uri) { - validateIncomingUri(uri); + uri = validateIncomingUri(uri); int userId = getUserIdFromUri(uri); uri = getUriWithoutUserId(uri); if (enforceReadPermission(callingPkg, uri, null) != AppOpsManager.MODE_ALLOWED) { @@ -467,7 +469,7 @@ public abstract class ContentProvider implements ComponentCallbacks2 { @Override public boolean refresh(String callingPkg, Uri uri, Bundle args, ICancellationSignal cancellationSignal) throws RemoteException { - validateIncomingUri(uri); + uri = validateIncomingUri(uri); uri = getUriWithoutUserId(uri); if (enforceReadPermission(callingPkg, uri, null) != AppOpsManager.MODE_ALLOWED) { return false; @@ -1901,7 +1903,7 @@ public abstract class ContentProvider implements ComponentCallbacks2 { */ if (mContext == null) { mContext = context; - if (context != null) { + if (context != null && mTransport != null) { mTransport.mAppOpsManager = (AppOpsManager) context.getSystemService( Context.APP_OPS_SERVICE); } @@ -2010,7 +2012,7 @@ public abstract class ContentProvider implements ComponentCallbacks2 { } /** @hide */ - private void validateIncomingUri(Uri uri) throws SecurityException { + public Uri validateIncomingUri(Uri uri) throws SecurityException { String auth = uri.getAuthority(); if (!mSingleUser) { int userId = getUserIdFromAuthority(auth, UserHandle.USER_CURRENT); @@ -2029,6 +2031,19 @@ public abstract class ContentProvider implements ComponentCallbacks2 { } throw new SecurityException(message); } + + // Normalize the path by removing any empty path segments, which can be + // a source of security issues. + final String encodedPath = uri.getEncodedPath(); + if (encodedPath != null && encodedPath.indexOf("//") != -1) { + final Uri normalized = uri.buildUpon() + .encodedPath(encodedPath.replaceAll("//+", "/")).build(); + Log.w(TAG, "Normalized " + uri + " to " + normalized + + " to avoid possible security issues"); + return normalized; + } else { + return uri; + } } /** @hide */ diff --git a/core/java/android/content/ContentProviderOperation.java b/core/java/android/content/ContentProviderOperation.java index 8f3a31746266..f3914f2a4e76 100644 --- a/core/java/android/content/ContentProviderOperation.java +++ b/core/java/android/content/ContentProviderOperation.java @@ -94,13 +94,9 @@ public class ContentProviderOperation implements Parcelable { } /** @hide */ - public ContentProviderOperation(ContentProviderOperation cpo, boolean removeUserIdFromUri) { + public ContentProviderOperation(ContentProviderOperation cpo, Uri withUri) { mType = cpo.mType; - if (removeUserIdFromUri) { - mUri = ContentProvider.getUriWithoutUserId(cpo.mUri); - } else { - mUri = cpo.mUri; - } + mUri = withUri; mValues = cpo.mValues; mSelection = cpo.mSelection; mSelectionArgs = cpo.mSelectionArgs; @@ -110,14 +106,6 @@ public class ContentProviderOperation implements Parcelable { mYieldAllowed = cpo.mYieldAllowed; } - /** @hide */ - public ContentProviderOperation getWithoutUserIdInUri() { - if (ContentProvider.uriHasUserId(mUri)) { - return new ContentProviderOperation(this, true); - } - return this; - } - public void writeToParcel(Parcel dest, int flags) { dest.writeInt(mType); Uri.writeToParcel(dest, mUri); -- cgit v1.2.3-59-g8ed1b From 7d4945ca8664c7e5def08ce4bbd6841a1bfac174 Mon Sep 17 00:00:00 2001 From: Tim Murray Date: Mon, 15 Oct 2018 16:29:15 -0700 Subject: hwui: purge malloc pages on bitmap destruction Immediately purge malloc pages on bitmap destruction. Bitmaps are often big and can cause memory to stay high for much longer than it should. Test: boots and works bug 117795621 Merged-in: If2e8c5f1fc07039cf3dc3edcd3dc06861dbce1a1 Change-Id: If2e8c5f1fc07039cf3dc3edcd3dc06861dbce1a1 (cherry picked from commit 535fae32e597445a480896ea8e01662ada444c0c) --- libs/hwui/hwui/Bitmap.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/hwui/hwui/Bitmap.cpp b/libs/hwui/hwui/Bitmap.cpp index 263d249d20e9..c6ef090c1f76 100644 --- a/libs/hwui/hwui/Bitmap.cpp +++ b/libs/hwui/hwui/Bitmap.cpp @@ -223,6 +223,7 @@ Bitmap::~Bitmap() { break; case PixelStorageType::Heap: free(mPixelStorage.heap.address); + mallopt(M_PURGE, 0); break; case PixelStorageType::Hardware: auto buffer = mPixelStorage.hardware.buffer; @@ -230,7 +231,6 @@ Bitmap::~Bitmap() { mPixelStorage.hardware.buffer = nullptr; break; } - android::uirenderer::renderthread::RenderProxy::onBitmapDestroyed(getStableID()); } -- cgit v1.2.3-59-g8ed1b From 64ea6ca2e39b779495feb695033c414ebfe62ac0 Mon Sep 17 00:00:00 2001 From: Tim Murray Date: Mon, 15 Oct 2018 16:50:23 -0700 Subject: wm: recycle bitmaps immediately in TaskSnapshotPersister Bitmap created in TaskSnapshotPersister are very short lived and shouldn't be left around in the Java heap. Test: boot, switch apps, works bug 117795621 Merged-in: I4b5e0db50c2b7adaa71cb0d22535c1b37c7523e8 Change-Id: I4b5e0db50c2b7adaa71cb0d22535c1b37c7523e8 (cherry picked from commit 9b4eaf740957663b01d4bf056df250dd028e0cb0) --- services/core/java/com/android/server/wm/TaskSnapshotPersister.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/services/core/java/com/android/server/wm/TaskSnapshotPersister.java b/services/core/java/com/android/server/wm/TaskSnapshotPersister.java index a642e6ab744a..d1c0443c58e1 100644 --- a/services/core/java/com/android/server/wm/TaskSnapshotPersister.java +++ b/services/core/java/com/android/server/wm/TaskSnapshotPersister.java @@ -360,6 +360,7 @@ class TaskSnapshotPersister { // For snapshots with reduced resolution, do not create or save full sized bitmaps if (mSnapshot.isReducedResolution()) { + swBitmap.recycle(); return true; } @@ -372,6 +373,8 @@ class TaskSnapshotPersister { Slog.e(TAG, "Unable to open " + file + " for persisting.", e); return false; } + reduced.recycle(); + swBitmap.recycle(); return true; } } -- cgit v1.2.3-59-g8ed1b From 7105e37a8c6d4dcf95695298486b25b8c43a6a7e Mon Sep 17 00:00:00 2001 From: Dan Sandler Date: Fri, 19 Oct 2018 18:12:40 -0400 Subject: Add configurable default setting for assistant componentname By requiring an explicit default setting, it eliminates all ambiguous states where a disambiguation would normally be shown. With this change in place, at no point should a disambiguation be shown. (Note: this is a fix to Change-Id: Ib32daf that clarifies the logic if R.string.config_defaultAssistantComponentName has not been set in a given build.) Test: manual Bug: 111603898 Change-Id: Id39fdf700ed4ef08ebbc333b5452223430ac2e48 Merged-In: Ib32dafbd3c6fcbe11186dc8ecab6b09c9b734067 (cherry picked from commit c6ed3a29f0e2f0f1ceb727c5ece07702987e4ba5) --- core/java/com/android/internal/app/AssistUtils.java | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/core/java/com/android/internal/app/AssistUtils.java b/core/java/com/android/internal/app/AssistUtils.java index 9171959537c8..fed0a89a4d75 100644 --- a/core/java/com/android/internal/app/AssistUtils.java +++ b/core/java/com/android/internal/app/AssistUtils.java @@ -32,6 +32,8 @@ import android.os.ServiceManager; import android.provider.Settings; import android.util.Log; +import com.android.internal.R; + /** * Utility method for dealing with the assistant aspects of * {@link com.android.internal.app.IVoiceInteractionManagerService IVoiceInteractionManagerService}. @@ -40,6 +42,14 @@ public class AssistUtils { private static final String TAG = "AssistUtils"; + /** + * Sentinel value for "no default assistant specified." + * + * Empty string is already used to represent an explicit setting of No Assistant. null cannot + * be used because we can't represent a null value in XML. + */ + private static final String UNSET = "#+UNSET"; + private final Context mContext; private final IVoiceInteractionManagerService mVoiceInteractionManagerService; @@ -152,10 +162,21 @@ public class AssistUtils { return ComponentName.unflattenFromString(setting); } + final String defaultSetting = mContext.getResources().getString( + R.string.config_defaultAssistantComponentName); + if (defaultSetting != null && !defaultSetting.equals(UNSET)) { + return ComponentName.unflattenFromString(defaultSetting); + } + // Fallback to keep backward compatible behavior when there is no user setting. if (activeServiceSupportsAssistGesture()) { return getActiveServiceComponentName(); } + + if (UNSET.equals(defaultSetting)) { + return null; + } + final SearchManager searchManager = (SearchManager) mContext.getSystemService(Context.SEARCH_SERVICE); if (searchManager == null) { -- cgit v1.2.3-59-g8ed1b