From 0e1f230112fba3a675e7cdbe05ec7c6621eca0d0 Mon Sep 17 00:00:00 2001 From: Fabrice Di Meglio Date: Wed, 6 Nov 2013 15:32:01 -0800 Subject: [PATCH 1/3] Fix bug #11537133 Hideycling looks broken (KOT36), missing left padding - enforce the Drawable boolean getPadding(Rect) contract for NinePatchDrawable and DrawableContainer. - as NinePatchDrawable was not enforcing it, the consequence was that the mUserPaddingLeftInitial / mUserPaddingRitghInitial were reset to "0" (even if they got the correct value before the reset). Change-Id: I1efe7fad5f89c0ca47f90189f6d89940e0e9c6ae --- graphics/java/android/graphics/drawable/DrawableContainer.java | 3 ++- graphics/java/android/graphics/drawable/NinePatchDrawable.java | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/graphics/java/android/graphics/drawable/DrawableContainer.java b/graphics/java/android/graphics/drawable/DrawableContainer.java index af8441a150a1c..aac78766514e4 100644 --- a/graphics/java/android/graphics/drawable/DrawableContainer.java +++ b/graphics/java/android/graphics/drawable/DrawableContainer.java @@ -88,9 +88,10 @@ public class DrawableContainer extends Drawable implements Drawable.Callback { @Override public boolean getPadding(Rect padding) { final Rect r = mDrawableContainerState.getConstantPadding(); - boolean result = true; + boolean result; if (r != null) { padding.set(r); + result = (r.left | r.top | r.bottom | r.right) != 0; } else { if (mCurrDrawable != null) { result = mCurrDrawable.getPadding(padding); diff --git a/graphics/java/android/graphics/drawable/NinePatchDrawable.java b/graphics/java/android/graphics/drawable/NinePatchDrawable.java index ab34c0fd5649a..9c57a2cec25c3 100644 --- a/graphics/java/android/graphics/drawable/NinePatchDrawable.java +++ b/graphics/java/android/graphics/drawable/NinePatchDrawable.java @@ -244,7 +244,7 @@ public class NinePatchDrawable extends Drawable { } else { padding.set(mPadding); } - return true; + return (padding.left | padding.top | padding.right | padding.bottom) != 0; } /** From 275232a73b3bed06785d263d1bf02ebeef9d6372 Mon Sep 17 00:00:00 2001 From: Fabrice Di Meglio Date: Wed, 6 Nov 2013 15:44:52 -0800 Subject: [PATCH 2/3] Improve RTL support for Immersive mode - use start/end instead of left/ritgh padding - related to bug #11537133 Hideycling looks broken (KOT36), missing left padding Change-Id: I0d8e1de560dbf142a3c016ab6d6784361d88d32a --- core/res/res/layout/immersive_mode_cling.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/res/res/layout/immersive_mode_cling.xml b/core/res/res/layout/immersive_mode_cling.xml index f97225eaeb9e2..c0cd93db456b6 100644 --- a/core/res/res/layout/immersive_mode_cling.xml +++ b/core/res/res/layout/immersive_mode_cling.xml @@ -37,8 +37,8 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:background="@drawable/cling_bg" - android:paddingLeft="14dp" - android:paddingRight="14dp" + android:paddingStart="14dp" + android:paddingEnd="14dp" android:paddingTop="24dp" android:paddingBottom="24dp"> Date: Wed, 6 Nov 2013 16:30:29 -0800 Subject: [PATCH 3/3] Fix issue #11223338: Not retaining service started state while restarting When I cleaned up how we maintained the lifecycle of the tracker with a service, I broke most tracking of the service restart state. (Since at that point the service is no longer associated with a process, so I must clean up the tracker state). This change introduces a new special case for interacting with a service tracker to explicitly tell it when a service is being restarted. It also fixes how we update the process state when services are attached to it, so it goes in and out of the restarting state correctly. In addition: - Maybe fix issue #11224000 (APR: Dependent processes not getting added to LRU list). We were not clearing ServiceRecord.app when bringing down a service, so if for some reason there were still connections to it at that point (which could happen for example for non-create bindings), then we would so it when updating the LRU state of that client process. - dumpsys procstats's package argument can now be a package or process name, and we will dump all relevent information we can find about that name. - Generally improved the quality of the dumpsys procstats output with its various options. - Fixed a bug in ActivityManager.dumpPackageState() where it would hang if the service was dumping too much, added meminfo to the set of things dumped, and tweaked command line options to include more data. - Added some more cleaning code to ActiveServices.killServices() to make sure we clean out any restarting ServiceRecord entries when a process is being force stopped. - Re-arranged ActiveServices.killServices() to do the main killing of the service first, to avoid some wtf() calls that could happen when removing connections. Bug: 11223338 Bug: 11224000 Change-Id: I5db28561c2c78aa43561e52256ff92c02311c56f --- core/java/android/app/ActivityManager.java | 9 +- .../android/internal/app/ProcessStats.java | 221 +++++++++++------- .../com/android/server/am/ActiveServices.java | 52 +++-- .../server/am/ActivityManagerService.java | 26 ++- .../android/server/am/ConnectionRecord.java | 2 +- .../server/am/ProcessStatsService.java | 32 +-- .../com/android/server/am/ServiceRecord.java | 21 ++ 7 files changed, 237 insertions(+), 126 deletions(-) diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java index bb04063905d51..7ca345993c232 100644 --- a/core/java/android/app/ActivityManager.java +++ b/core/java/android/app/ActivityManager.java @@ -2272,9 +2272,12 @@ public class ActivityManager { public static void dumpPackageStateStatic(FileDescriptor fd, String packageName) { FileOutputStream fout = new FileOutputStream(fd); PrintWriter pw = new FastPrintWriter(fout); - dumpService(pw, fd, Context.ACTIVITY_SERVICE, new String[] { "package", packageName }); + dumpService(pw, fd, Context.ACTIVITY_SERVICE, new String[] { + "-a", "package", packageName }); pw.println(); - dumpService(pw, fd, ProcessStats.SERVICE_NAME, new String[] { packageName }); + dumpService(pw, fd, "meminfo", new String[] { "--local", packageName }); + pw.println(); + dumpService(pw, fd, ProcessStats.SERVICE_NAME, new String[] { "-a", packageName }); pw.println(); dumpService(pw, fd, "usagestats", new String[] { "--packages", packageName }); pw.println(); @@ -2296,7 +2299,7 @@ public class ActivityManager { pw.flush(); tp = new TransferPipe(); tp.setBufferPrefix(" "); - service.dump(tp.getWriteFd().getFileDescriptor(), args); + service.dumpAsync(tp.getWriteFd().getFileDescriptor(), args); tp.go(fd); } catch (Throwable e) { if (tp != null) { diff --git a/core/java/com/android/internal/app/ProcessStats.java b/core/java/com/android/internal/app/ProcessStats.java index 20b8c95164cdb..0cad33cff6b8b 100644 --- a/core/java/com/android/internal/app/ProcessStats.java +++ b/core/java/com/android/internal/app/ProcessStats.java @@ -1758,21 +1758,34 @@ public final class ProcessStats implements Parcelable { mStartTime, now); ArrayMap> pkgMap = mPackages.getMap(); boolean printedHeader = false; + boolean sepNeeded = false; for (int ip=0; ip uids = pkgMap.valueAt(ip); + final String pkgName = pkgMap.keyAt(ip); + final SparseArray uids = pkgMap.valueAt(ip); for (int iu=0; iu 0 || NSRVS > 0) { if (!printedHeader) { pw.println("Per-Package Stats:"); printedHeader = true; + sepNeeded = true; } pw.print(" * "); pw.print(pkgName); pw.print(" / "); UserHandle.formatUid(pw, uid); pw.println(":"); @@ -1780,6 +1793,9 @@ public final class ProcessStats implements Parcelable { if (!dumpSummary || dumpAll) { for (int iproc=0; iproc procs = new ArrayList(); for (int iproc=0; iproc> procMap = mProcesses.getMap(); + printedHeader = false; + int numShownProcs = 0, numTotalProcs = 0; + for (int ip=0; ip uids = procMap.valueAt(ip); + for (int iu=0; iu collectProcessesLocked(int[] screenStates, int[] memStates, int[] procStates, int sortProcStates[], long now, String reqPackage, boolean activeOnly) { - ArraySet foundProcs = new ArraySet(); - ArrayMap> pkgMap = mPackages.getMap(); + final ArraySet foundProcs = new ArraySet(); + final ArrayMap> pkgMap = mPackages.getMap(); for (int ip=0; ip procs = pkgMap.valueAt(ip); + final String pkgName = pkgMap.keyAt(ip); + final SparseArray procs = pkgMap.valueAt(ip); for (int iu=0; iu=0; i--) { - ConnectionRecord r = app.connections.valueAt(i); - removeConnectionLocked(r, app, null); - } - app.connections.clear(); - + // First clear app state from services. for (int i=app.services.size()-1; i>=0; i--) { - // Any services running in the application need to be placed - // back in the pending list. ServiceRecord sr = app.services.valueAt(i); synchronized (sr.stats.getBatteryStats()) { sr.stats.stopLaunchedLocked(); @@ -2020,8 +2020,21 @@ public final class ActiveServices { b.binder = null; b.requested = b.received = b.hasBound = false; } + } - if (sr.crashCount >= 2 && (sr.serviceInfo.applicationInfo.flags + // Clean up any connections this application has to other services. + for (int i=app.connections.size()-1; i>=0; i--) { + ConnectionRecord r = app.connections.valueAt(i); + removeConnectionLocked(r, app, null); + } + app.connections.clear(); + + // Now do remaining service cleanup. + for (int i=app.services.size()-1; i>=0; i--) { + // Any services running in the application may need to be placed + // back in the pending list. + ServiceRecord sr = app.services.valueAt(i); + if (allowRestart && sr.crashCount >= 2 && (sr.serviceInfo.applicationInfo.flags &ApplicationInfo.FLAG_PERSISTENT) == 0) { Slog.w(TAG, "Service crashed " + sr.crashCount + " times, stopping: " + sr); @@ -2054,6 +2067,17 @@ public final class ActiveServices { if (!allowRestart) { app.services.clear(); + + // Make sure there are no more restarting services for this process. + for (int i=mRestartingServices.size()-1; i>=0; i--) { + ServiceRecord r = mRestartingServices.get(i); + if (r.processName.equals(app.processName) && + r.serviceInfo.applicationInfo.uid == app.info.uid) { + mRestartingServices.remove(i); + r.clearRestarting(mAm.mProcessStats.getMemFactorLocked(), + SystemClock.uptimeMillis()); + } + } } // Make sure we have no more records on the stopping list. diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java index 164e7b7201ad9..fe83e9f2695e7 100644 --- a/services/java/com/android/server/am/ActivityManagerService.java +++ b/services/java/com/android/server/am/ActivityManagerService.java @@ -11901,6 +11901,7 @@ public final class ActivityManagerService extends ActivityManagerNative boolean dumpDalvik = false; boolean oomOnly = false; boolean isCompact = false; + boolean localOnly = false; int opti = 0; while (opti < args.length) { @@ -11919,12 +11920,15 @@ public final class ActivityManagerService extends ActivityManagerNative isCompact = true; } else if ("--oom".equals(opt)) { oomOnly = true; + } else if ("--local".equals(opt)) { + localOnly = true; } else if ("-h".equals(opt)) { pw.println("meminfo dump options: [-a] [-d] [-c] [--oom] [process]"); pw.println(" -a: include all available information for each process."); pw.println(" -d: include dalvik details when dumping process details."); pw.println(" -c: dump in a compact machine-parseable representation."); pw.println(" --oom: only show processes organized by oom adj."); + pw.println(" --local: only collect details locally, don't call process."); pw.println("If [process] is specified it can be the name or "); pw.println("pid of a specific process to dump."); return; @@ -12041,14 +12045,22 @@ public final class ActivityManagerService extends ActivityManagerNative mi.dalvikPrivateDirty = (int)tmpLong[0]; } if (dumpDetails) { - try { - pw.flush(); - thread.dumpMemInfo(fd, mi, isCheckinRequest, dumpFullDetails, - dumpDalvik, innerArgs); - } catch (RemoteException e) { - if (!isCheckinRequest) { - pw.println("Got RemoteException!"); + if (localOnly) { + ActivityThread.dumpMemInfoTable(pw, mi, isCheckinRequest, dumpFullDetails, + dumpDalvik, pid, r.processName, 0, 0, 0, 0, 0, 0); + if (isCheckinRequest) { + pw.println(); + } + } else { + try { pw.flush(); + thread.dumpMemInfo(fd, mi, isCheckinRequest, dumpFullDetails, + dumpDalvik, innerArgs); + } catch (RemoteException e) { + if (!isCheckinRequest) { + pw.println("Got RemoteException!"); + pw.flush(); + } } } } diff --git a/services/java/com/android/server/am/ConnectionRecord.java b/services/java/com/android/server/am/ConnectionRecord.java index 576adc26a5798..423e540229dba 100644 --- a/services/java/com/android/server/am/ConnectionRecord.java +++ b/services/java/com/android/server/am/ConnectionRecord.java @@ -27,7 +27,7 @@ import java.io.PrintWriter; */ final class ConnectionRecord { final AppBindRecord binding; // The application/service binding. - final ActivityRecord activity; // If non-null, the owning activity. + final ActivityRecord activity; // If non-null, the owning activity. final IServiceConnection conn; // The client connection. final int flags; // Binding options. final int clientLabel; // String resource labeling this client. diff --git a/services/java/com/android/server/am/ProcessStatsService.java b/services/java/com/android/server/am/ProcessStatsService.java index 8d168807bbd8d..e05fcda70ff06 100644 --- a/services/java/com/android/server/am/ProcessStatsService.java +++ b/services/java/com/android/server/am/ProcessStatsService.java @@ -750,23 +750,12 @@ public final class ProcessStatsService extends IProcessStats.Stub { return; } else { // Not an option, last argument must be a package name. - try { - IPackageManager pm = AppGlobals.getPackageManager(); - if (pm.getPackageUid(arg, UserHandle.getCallingUserId()) >= 0) { - reqPackage = arg; - // Include all details, since we know we are only going to - // be dumping a smaller set of data. In fact only the details - // container per-package data, so that are needed to be able - // to dump anything at all when filtering by package. - dumpDetails = true; - } - } catch (RemoteException e) { - } - if (reqPackage == null) { - pw.println("Unknown package: " + arg); - dumpHelp(pw); - return; - } + reqPackage = arg; + // Include all details, since we know we are only going to + // be dumping a smaller set of data. In fact only the details + // container per-package data, so that are needed to be able + // to dump anything at all when filtering by package. + dumpDetails = true; } } } @@ -816,13 +805,14 @@ public final class ProcessStatsService extends IProcessStats.Stub { } return; } else if (aggregateHours != 0) { + pw.print("AGGREGATED OVER LAST "); pw.print(aggregateHours); pw.println(" HOURS:"); dumpAggregatedStats(pw, aggregateHours, now, reqPackage, isCompact, dumpDetails, dumpFullDetails, dumpAll, activeOnly); return; } boolean sepNeeded = false; - if (!currentOnly || isCheckin) { + if (dumpAll || isCheckin) { mWriteLock.lock(); try { ArrayList files = getCommittedFiles(0, false, !isCheckin); @@ -882,11 +872,11 @@ public final class ProcessStatsService extends IProcessStats.Stub { } } if (!isCheckin) { - if (dumpAll) { + if (!currentOnly) { if (sepNeeded) { pw.println(); - pw.println("AGGREGATED OVER LAST 24 HOURS:"); } + pw.println("AGGREGATED OVER LAST 24 HOURS:"); dumpAggregatedStats(pw, 24, now, reqPackage, isCompact, dumpDetails, dumpFullDetails, dumpAll, activeOnly); pw.println(); @@ -901,8 +891,8 @@ public final class ProcessStatsService extends IProcessStats.Stub { } else { if (sepNeeded) { pw.println(); - pw.println("CURRENT STATS:"); } + pw.println("CURRENT STATS:"); if (dumpDetails || dumpFullDetails) { mProcessStats.dumpLocked(pw, reqPackage, now, !dumpFullDetails, dumpAll, activeOnly); diff --git a/services/java/com/android/server/am/ServiceRecord.java b/services/java/com/android/server/am/ServiceRecord.java index cc1172a8cccd3..84b1c3a432cd9 100644 --- a/services/java/com/android/server/am/ServiceRecord.java +++ b/services/java/com/android/server/am/ServiceRecord.java @@ -85,6 +85,7 @@ final class ServiceRecord extends Binder { ProcessRecord app; // where this service is running or null. ProcessRecord isolatedProc; // keep track of isolated process, if requested ProcessStats.ServiceState tracker; // tracking service execution, may be null + ProcessStats.ServiceState restartTracker; // tracking service restart boolean delayed; // are we waiting to start this service in the background? boolean isForeground; // is service currently in foreground mode? int foregroundId; // Notification ID of last foreground req. @@ -340,6 +341,26 @@ final class ServiceRecord extends Binder { } } + public void makeRestarting(int memFactor, long now) { + if (restartTracker == null) { + if ((serviceInfo.applicationInfo.flags&ApplicationInfo.FLAG_PERSISTENT) == 0) { + restartTracker = ams.mProcessStats.getServiceStateLocked(serviceInfo.packageName, + serviceInfo.applicationInfo.uid, serviceInfo.processName, serviceInfo.name); + } + if (restartTracker == null) { + return; + } + } + restartTracker.setRestarting(true, memFactor, now); + } + + public void clearRestarting(int memFactor, long now) { + if (restartTracker != null) { + restartTracker.setRestarting(false, memFactor, now); + restartTracker = null; + } + } + public AppBindRecord retrieveAppBindingLocked(Intent intent, ProcessRecord app) { Intent.FilterComparison filter = new Intent.FilterComparison(intent);