Reclaim more memory, more often.
Yay. Change-Id: I04557ad575c307a55088549f48f0e9ad994b7275
This commit is contained in:
@ -123,7 +123,6 @@ public final class ActivityThread {
|
||||
/** @hide */
|
||||
public static final String TAG = "ActivityThread";
|
||||
private static final android.graphics.Bitmap.Config THUMBNAIL_FORMAT = Bitmap.Config.RGB_565;
|
||||
private static final boolean DEBUG = false;
|
||||
static final boolean localLOGV = false;
|
||||
static final boolean DEBUG_MESSAGES = false;
|
||||
/** @hide */
|
||||
@ -163,7 +162,7 @@ public final class ActivityThread {
|
||||
= new ArrayList<Application>();
|
||||
// set of instantiated backup agents, keyed by package name
|
||||
final HashMap<String, BackupAgent> mBackupAgents = new HashMap<String, BackupAgent>();
|
||||
static final ThreadLocal<ActivityThread> sThreadLocal = new ThreadLocal();
|
||||
static final ThreadLocal<ActivityThread> sThreadLocal = new ThreadLocal<ActivityThread>();
|
||||
Instrumentation mInstrumentation;
|
||||
String mInstrumentationAppDir = null;
|
||||
String mInstrumentationAppPackage = null;
|
||||
@ -410,9 +409,9 @@ public final class ActivityThread {
|
||||
CompatibilityInfo info;
|
||||
}
|
||||
|
||||
native private void dumpGraphicsInfo(FileDescriptor fd);
|
||||
private native void dumpGraphicsInfo(FileDescriptor fd);
|
||||
|
||||
private final class ApplicationThread extends ApplicationThreadNative {
|
||||
private class ApplicationThread extends ApplicationThreadNative {
|
||||
private static final String HEAP_COLUMN = "%13s %8s %8s %8s %8s %8s %8s";
|
||||
private static final String ONE_COUNT_COLUMN = "%21s %8d";
|
||||
private static final String TWO_COUNT_COLUMNS = "%21s %8d %21s %8d";
|
||||
@ -734,13 +733,13 @@ public final class ActivityThread {
|
||||
FileOutputStream fout = new FileOutputStream(fd);
|
||||
PrintWriter pw = new PrintWriter(fout);
|
||||
try {
|
||||
return dumpMemInfo(fd, pw, args);
|
||||
return dumpMemInfo(pw, args);
|
||||
} finally {
|
||||
pw.flush();
|
||||
}
|
||||
}
|
||||
|
||||
private Debug.MemoryInfo dumpMemInfo(FileDescriptor fd, PrintWriter pw, String[] args) {
|
||||
private Debug.MemoryInfo dumpMemInfo(PrintWriter pw, String[] args) {
|
||||
long nativeMax = Debug.getNativeHeapSize() / 1024;
|
||||
long nativeAllocated = Debug.getNativeHeapAllocatedSize() / 1024;
|
||||
long nativeFree = Debug.getNativeHeapFreeSize() / 1024;
|
||||
@ -754,7 +753,7 @@ public final class ActivityThread {
|
||||
long dalvikFree = runtime.freeMemory() / 1024;
|
||||
long dalvikAllocated = dalvikMax - dalvikFree;
|
||||
long viewInstanceCount = ViewDebug.getViewInstanceCount();
|
||||
long viewRootInstanceCount = ViewDebug.getViewAncestorInstanceCount();
|
||||
long viewRootInstanceCount = ViewDebug.getViewRootImplCount();
|
||||
long appContextInstanceCount = Debug.countInstancesOfClass(ContextImpl.class);
|
||||
long activityInstanceCount = Debug.countInstancesOfClass(Activity.class);
|
||||
int globalAssetCount = AssetManager.getGlobalAssetCount();
|
||||
@ -868,7 +867,7 @@ public final class ActivityThread {
|
||||
int otherPrivateDirty = memInfo.otherPrivateDirty;
|
||||
|
||||
for (int i=0; i<Debug.MemoryInfo.NUM_OTHER_STATS; i++) {
|
||||
printRow(pw, HEAP_COLUMN, memInfo.getOtherLabel(i),
|
||||
printRow(pw, HEAP_COLUMN, Debug.MemoryInfo.getOtherLabel(i),
|
||||
memInfo.getOtherPss(i), memInfo.getOtherSharedDirty(i),
|
||||
memInfo.getOtherPrivateDirty(i), "", "", "");
|
||||
otherPss -= memInfo.getOtherPss(i);
|
||||
@ -885,7 +884,7 @@ public final class ActivityThread {
|
||||
|
||||
pw.println(" ");
|
||||
pw.println(" Objects");
|
||||
printRow(pw, TWO_COUNT_COLUMNS, "Views:", viewInstanceCount, "ViewAncestors:",
|
||||
printRow(pw, TWO_COUNT_COLUMNS, "Views:", viewInstanceCount, "ViewRootImpl:",
|
||||
viewRootInstanceCount);
|
||||
|
||||
printRow(pw, TWO_COUNT_COLUMNS, "AppContexts:", appContextInstanceCount,
|
||||
@ -937,6 +936,7 @@ public final class ActivityThread {
|
||||
@Override
|
||||
public void dumpGfxInfo(FileDescriptor fd, String[] args) {
|
||||
dumpGraphicsInfo(fd);
|
||||
WindowManagerImpl.getDefault().dumpGfxInfo(fd);
|
||||
}
|
||||
|
||||
private void printRow(PrintWriter pw, String format, Object...objs) {
|
||||
@ -959,7 +959,7 @@ public final class ActivityThread {
|
||||
}
|
||||
}
|
||||
|
||||
private final class H extends Handler {
|
||||
private class H extends Handler {
|
||||
public static final int LAUNCH_ACTIVITY = 100;
|
||||
public static final int PAUSE_ACTIVITY = 101;
|
||||
public static final int PAUSE_ACTIVITY_FINISHING= 102;
|
||||
@ -1220,7 +1220,7 @@ public final class ActivityThread {
|
||||
}
|
||||
}
|
||||
|
||||
private final class Idler implements MessageQueue.IdleHandler {
|
||||
private class Idler implements MessageQueue.IdleHandler {
|
||||
public final boolean queueIdle() {
|
||||
ActivityClientRecord a = mNewActivities;
|
||||
if (a != null) {
|
||||
@ -1231,12 +1231,13 @@ public final class ActivityThread {
|
||||
if (localLOGV) Slog.v(
|
||||
TAG, "Reporting idle of " + a +
|
||||
" finished=" +
|
||||
(a.activity != null ? a.activity.mFinished : false));
|
||||
(a.activity != null && a.activity.mFinished));
|
||||
if (a.activity != null && !a.activity.mFinished) {
|
||||
try {
|
||||
am.activityIdle(a.token, a.createdConfig);
|
||||
a.createdConfig = null;
|
||||
} catch (RemoteException ex) {
|
||||
// Ignore
|
||||
}
|
||||
}
|
||||
prev = a;
|
||||
@ -1256,7 +1257,7 @@ public final class ActivityThread {
|
||||
}
|
||||
}
|
||||
|
||||
private final static class ResourcesKey {
|
||||
private static class ResourcesKey {
|
||||
final private String mResDir;
|
||||
final private float mScale;
|
||||
final private int mHash;
|
||||
@ -1282,17 +1283,17 @@ public final class ActivityThread {
|
||||
}
|
||||
}
|
||||
|
||||
public static final ActivityThread currentActivityThread() {
|
||||
public static ActivityThread currentActivityThread() {
|
||||
return sThreadLocal.get();
|
||||
}
|
||||
|
||||
public static final String currentPackageName() {
|
||||
public static String currentPackageName() {
|
||||
ActivityThread am = currentActivityThread();
|
||||
return (am != null && am.mBoundApplication != null)
|
||||
? am.mBoundApplication.processName : null;
|
||||
}
|
||||
|
||||
public static final Application currentApplication() {
|
||||
public static Application currentApplication() {
|
||||
ActivityThread am = currentActivityThread();
|
||||
return am != null ? am.mInitialApplication : null;
|
||||
}
|
||||
@ -1337,7 +1338,7 @@ public final class ActivityThread {
|
||||
return config;
|
||||
}
|
||||
|
||||
private final Configuration mMainThreadConfig = new Configuration();
|
||||
private Configuration mMainThreadConfig = new Configuration();
|
||||
Configuration applyConfigCompatMainThread(Configuration config, CompatibilityInfo compat) {
|
||||
if (config == null) {
|
||||
return null;
|
||||
@ -1456,6 +1457,7 @@ public final class ActivityThread {
|
||||
ai = getPackageManager().getApplicationInfo(packageName,
|
||||
PackageManager.GET_SHARED_LIBRARY_FILES);
|
||||
} catch (RemoteException e) {
|
||||
// Ignore
|
||||
}
|
||||
|
||||
if (ai != null) {
|
||||
@ -1505,7 +1507,7 @@ public final class ActivityThread {
|
||||
}
|
||||
}
|
||||
|
||||
private final LoadedApk getPackageInfo(ApplicationInfo aInfo, CompatibilityInfo compatInfo,
|
||||
private LoadedApk getPackageInfo(ApplicationInfo aInfo, CompatibilityInfo compatInfo,
|
||||
ClassLoader baseLoader, boolean securityViolation, boolean includeCode) {
|
||||
synchronized (mPackages) {
|
||||
WeakReference<LoadedApk> ref;
|
||||
@ -1712,15 +1714,15 @@ public final class ActivityThread {
|
||||
|
||||
// if the thread hasn't started yet, we don't have the handler, so just
|
||||
// save the messages until we're ready.
|
||||
private final void queueOrSendMessage(int what, Object obj) {
|
||||
private void queueOrSendMessage(int what, Object obj) {
|
||||
queueOrSendMessage(what, obj, 0, 0);
|
||||
}
|
||||
|
||||
private final void queueOrSendMessage(int what, Object obj, int arg1) {
|
||||
private void queueOrSendMessage(int what, Object obj, int arg1) {
|
||||
queueOrSendMessage(what, obj, arg1, 0);
|
||||
}
|
||||
|
||||
private final void queueOrSendMessage(int what, Object obj, int arg1, int arg2) {
|
||||
private void queueOrSendMessage(int what, Object obj, int arg1, int arg2) {
|
||||
synchronized (this) {
|
||||
if (DEBUG_MESSAGES) Slog.v(
|
||||
TAG, "SCHEDULE " + what + " " + mH.codeToString(what)
|
||||
@ -1743,7 +1745,7 @@ public final class ActivityThread {
|
||||
queueOrSendMessage(H.CLEAN_UP_CONTEXT, cci);
|
||||
}
|
||||
|
||||
private final Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
|
||||
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
|
||||
// System.out.println("##### [" + System.currentTimeMillis() + "] ActivityThread.performLaunchActivity(" + r + ")");
|
||||
|
||||
ActivityInfo aInfo = r.activityInfo;
|
||||
@ -1861,7 +1863,7 @@ public final class ActivityThread {
|
||||
return activity;
|
||||
}
|
||||
|
||||
private final void handleLaunchActivity(ActivityClientRecord r, Intent customIntent) {
|
||||
private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent) {
|
||||
// If we are getting ready to gc after going to the background, well
|
||||
// we are back active so skip it.
|
||||
unscheduleGcIdler();
|
||||
@ -1917,11 +1919,12 @@ public final class ActivityThread {
|
||||
ActivityManagerNative.getDefault()
|
||||
.finishActivity(r.token, Activity.RESULT_CANCELED, null);
|
||||
} catch (RemoteException ex) {
|
||||
// Ignore
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private final void deliverNewIntents(ActivityClientRecord r,
|
||||
private void deliverNewIntents(ActivityClientRecord r,
|
||||
List<Intent> intents) {
|
||||
final int N = intents.size();
|
||||
for (int i=0; i<N; i++) {
|
||||
@ -1949,7 +1952,7 @@ public final class ActivityThread {
|
||||
}
|
||||
}
|
||||
|
||||
private final void handleNewIntent(NewIntentData data) {
|
||||
private void handleNewIntent(NewIntentData data) {
|
||||
performNewIntents(data.token, data.intents);
|
||||
}
|
||||
|
||||
@ -1964,7 +1967,7 @@ public final class ActivityThread {
|
||||
return sCurrentBroadcastIntent.get();
|
||||
}
|
||||
|
||||
private final void handleReceiver(ReceiverData data) {
|
||||
private void handleReceiver(ReceiverData data) {
|
||||
// If we are getting ready to gc after going to the background, well
|
||||
// we are back active so skip it.
|
||||
unscheduleGcIdler();
|
||||
@ -1976,7 +1979,7 @@ public final class ActivityThread {
|
||||
|
||||
IActivityManager mgr = ActivityManagerNative.getDefault();
|
||||
|
||||
BroadcastReceiver receiver = null;
|
||||
BroadcastReceiver receiver;
|
||||
try {
|
||||
java.lang.ClassLoader cl = packageInfo.getClassLoader();
|
||||
data.intent.setExtrasClassLoader(cl);
|
||||
@ -2026,7 +2029,7 @@ public final class ActivityThread {
|
||||
}
|
||||
|
||||
// Instantiate a BackupAgent and tell it that it's alive
|
||||
private final void handleCreateBackupAgent(CreateBackupAgentData data) {
|
||||
private void handleCreateBackupAgent(CreateBackupAgentData data) {
|
||||
if (DEBUG_BACKUP) Slog.v(TAG, "handleCreateBackupAgent: " + data);
|
||||
|
||||
// no longer idle; we have backup work to do
|
||||
@ -2091,7 +2094,7 @@ public final class ActivityThread {
|
||||
}
|
||||
|
||||
// Tear down a BackupAgent
|
||||
private final void handleDestroyBackupAgent(CreateBackupAgentData data) {
|
||||
private void handleDestroyBackupAgent(CreateBackupAgentData data) {
|
||||
if (DEBUG_BACKUP) Slog.v(TAG, "handleDestroyBackupAgent: " + data);
|
||||
|
||||
LoadedApk packageInfo = getPackageInfoNoCheck(data.appInfo, data.compatInfo);
|
||||
@ -2110,7 +2113,7 @@ public final class ActivityThread {
|
||||
}
|
||||
}
|
||||
|
||||
private final void handleCreateService(CreateServiceData data) {
|
||||
private void handleCreateService(CreateServiceData data) {
|
||||
// If we are getting ready to gc after going to the background, well
|
||||
// we are back active so skip it.
|
||||
unscheduleGcIdler();
|
||||
@ -2156,7 +2159,7 @@ public final class ActivityThread {
|
||||
}
|
||||
}
|
||||
|
||||
private final void handleBindService(BindServiceData data) {
|
||||
private void handleBindService(BindServiceData data) {
|
||||
Service s = mServices.get(data.token);
|
||||
if (s != null) {
|
||||
try {
|
||||
@ -2184,7 +2187,7 @@ public final class ActivityThread {
|
||||
}
|
||||
}
|
||||
|
||||
private final void handleUnbindService(BindServiceData data) {
|
||||
private void handleUnbindService(BindServiceData data) {
|
||||
Service s = mServices.get(data.token);
|
||||
if (s != null) {
|
||||
try {
|
||||
@ -2236,7 +2239,7 @@ public final class ActivityThread {
|
||||
}
|
||||
}
|
||||
|
||||
private final void handleServiceArgs(ServiceArgsData data) {
|
||||
private void handleServiceArgs(ServiceArgsData data) {
|
||||
Service s = mServices.get(data.token);
|
||||
if (s != null) {
|
||||
try {
|
||||
@ -2270,7 +2273,7 @@ public final class ActivityThread {
|
||||
}
|
||||
}
|
||||
|
||||
private final void handleStopService(IBinder token) {
|
||||
private void handleStopService(IBinder token) {
|
||||
Service s = mServices.remove(token);
|
||||
if (s != null) {
|
||||
try {
|
||||
@ -2465,7 +2468,7 @@ public final class ActivityThread {
|
||||
private Bitmap mAvailThumbnailBitmap = null;
|
||||
private Canvas mThumbnailCanvas = null;
|
||||
|
||||
private final Bitmap createThumbnailBitmap(ActivityClientRecord r) {
|
||||
private Bitmap createThumbnailBitmap(ActivityClientRecord r) {
|
||||
Bitmap thumbnail = mAvailThumbnailBitmap;
|
||||
try {
|
||||
if (thumbnail == null) {
|
||||
@ -2515,7 +2518,7 @@ public final class ActivityThread {
|
||||
return thumbnail;
|
||||
}
|
||||
|
||||
private final void handlePauseActivity(IBinder token, boolean finished,
|
||||
private void handlePauseActivity(IBinder token, boolean finished,
|
||||
boolean userLeaving, int configChanges) {
|
||||
ActivityClientRecord r = mActivities.get(token);
|
||||
if (r != null) {
|
||||
@ -2621,7 +2624,7 @@ public final class ActivityThread {
|
||||
CharSequence description;
|
||||
}
|
||||
|
||||
private final class ProviderRefCount {
|
||||
private class ProviderRefCount {
|
||||
public int count;
|
||||
ProviderRefCount(int pCount) {
|
||||
count = pCount;
|
||||
@ -2636,7 +2639,7 @@ public final class ActivityThread {
|
||||
* For the client, we want to call onStop()/onStart() to indicate when
|
||||
* the activity's UI visibillity changes.
|
||||
*/
|
||||
private final void performStopActivityInner(ActivityClientRecord r,
|
||||
private void performStopActivityInner(ActivityClientRecord r,
|
||||
StopInfo info, boolean keepShown, boolean saveState) {
|
||||
if (localLOGV) Slog.v(TAG, "Performing stop of " + r);
|
||||
Bundle state = null;
|
||||
@ -2699,7 +2702,7 @@ public final class ActivityThread {
|
||||
}
|
||||
}
|
||||
|
||||
private final void updateVisibility(ActivityClientRecord r, boolean show) {
|
||||
private void updateVisibility(ActivityClientRecord r, boolean show) {
|
||||
View v = r.activity.mDecor;
|
||||
if (v != null) {
|
||||
if (show) {
|
||||
@ -2726,7 +2729,7 @@ public final class ActivityThread {
|
||||
}
|
||||
}
|
||||
|
||||
private final void handleStopActivity(IBinder token, boolean show, int configChanges) {
|
||||
private void handleStopActivity(IBinder token, boolean show, int configChanges) {
|
||||
ActivityClientRecord r = mActivities.get(token);
|
||||
r.activity.mConfigChangeFlags |= configChanges;
|
||||
|
||||
@ -2760,7 +2763,7 @@ public final class ActivityThread {
|
||||
}
|
||||
}
|
||||
|
||||
private final void handleWindowVisibility(IBinder token, boolean show) {
|
||||
private void handleWindowVisibility(IBinder token, boolean show) {
|
||||
ActivityClientRecord r = mActivities.get(token);
|
||||
|
||||
if (r == null) {
|
||||
@ -2785,7 +2788,7 @@ public final class ActivityThread {
|
||||
}
|
||||
}
|
||||
|
||||
private final void handleSleeping(IBinder token, boolean sleeping) {
|
||||
private void handleSleeping(IBinder token, boolean sleeping) {
|
||||
ActivityClientRecord r = mActivities.get(token);
|
||||
|
||||
if (r == null) {
|
||||
@ -2846,7 +2849,7 @@ public final class ActivityThread {
|
||||
WindowManagerImpl.getDefault().reportNewConfiguration(mConfiguration);
|
||||
}
|
||||
|
||||
private final void deliverResults(ActivityClientRecord r, List<ResultInfo> results) {
|
||||
private void deliverResults(ActivityClientRecord r, List<ResultInfo> results) {
|
||||
final int N = results.size();
|
||||
for (int i=0; i<N; i++) {
|
||||
ResultInfo ri = results.get(i);
|
||||
@ -2869,7 +2872,7 @@ public final class ActivityThread {
|
||||
}
|
||||
}
|
||||
|
||||
private final void handleSendResult(ResultData res) {
|
||||
private void handleSendResult(ResultData res) {
|
||||
ActivityClientRecord r = mActivities.get(res.token);
|
||||
if (DEBUG_RESULTS) Slog.v(TAG, "Handling send result to " + r);
|
||||
if (r != null) {
|
||||
@ -2915,7 +2918,7 @@ public final class ActivityThread {
|
||||
return performDestroyActivity(token, finishing, 0, false);
|
||||
}
|
||||
|
||||
private final ActivityClientRecord performDestroyActivity(IBinder token, boolean finishing,
|
||||
private ActivityClientRecord performDestroyActivity(IBinder token, boolean finishing,
|
||||
int configChanges, boolean getNonConfigInstance) {
|
||||
ActivityClientRecord r = mActivities.get(token);
|
||||
Class activityClass = null;
|
||||
@ -3008,7 +3011,7 @@ public final class ActivityThread {
|
||||
return component == null ? "[Unknown]" : component.toShortString();
|
||||
}
|
||||
|
||||
private final void handleDestroyActivity(IBinder token, boolean finishing,
|
||||
private void handleDestroyActivity(IBinder token, boolean finishing,
|
||||
int configChanges, boolean getNonConfigInstance) {
|
||||
ActivityClientRecord r = performDestroyActivity(token, finishing,
|
||||
configChanges, getNonConfigInstance);
|
||||
@ -3123,7 +3126,7 @@ public final class ActivityThread {
|
||||
}
|
||||
}
|
||||
|
||||
private final void handleRelaunchActivity(ActivityClientRecord tmp) {
|
||||
private void handleRelaunchActivity(ActivityClientRecord tmp) {
|
||||
// If we are getting ready to gc after going to the background, well
|
||||
// we are back active so skip it.
|
||||
unscheduleGcIdler();
|
||||
@ -3233,7 +3236,7 @@ public final class ActivityThread {
|
||||
handleLaunchActivity(r, currentIntent);
|
||||
}
|
||||
|
||||
private final void handleRequestThumbnail(IBinder token) {
|
||||
private void handleRequestThumbnail(IBinder token) {
|
||||
ActivityClientRecord r = mActivities.get(token);
|
||||
Bitmap thumbnail = createThumbnailBitmap(r);
|
||||
CharSequence description = null;
|
||||
@ -3308,7 +3311,7 @@ public final class ActivityThread {
|
||||
return callbacks;
|
||||
}
|
||||
|
||||
private final void performConfigurationChanged(
|
||||
private void performConfigurationChanged(
|
||||
ComponentCallbacks cb, Configuration config) {
|
||||
// Only for Activity objects, check that they actually call up to their
|
||||
// superclass implementation. ComponentCallbacks is an interface, so
|
||||
@ -3451,6 +3454,9 @@ public final class ActivityThread {
|
||||
}
|
||||
callbacks = collectComponentCallbacksLocked(false, config);
|
||||
}
|
||||
|
||||
// Cleanup hardware accelerated stuff
|
||||
WindowManagerImpl.getDefault().trimLocalMemory();
|
||||
|
||||
if (callbacks != null) {
|
||||
final int N = callbacks.size();
|
||||
@ -3579,7 +3585,7 @@ public final class ActivityThread {
|
||||
WindowManagerImpl.getDefault().trimMemory(level);
|
||||
}
|
||||
|
||||
private final void handleBindApplication(AppBindData data) {
|
||||
private void handleBindApplication(AppBindData data) {
|
||||
mBoundApplication = data;
|
||||
mConfiguration = new Configuration(data.config);
|
||||
mCompatConfiguration = new Configuration(data.config);
|
||||
@ -3791,7 +3797,7 @@ public final class ActivityThread {
|
||||
}
|
||||
}
|
||||
|
||||
private final void installContentProviders(
|
||||
private void installContentProviders(
|
||||
Context context, List<ProviderInfo> providers) {
|
||||
final ArrayList<IActivityManager.ContentProviderHolder> results =
|
||||
new ArrayList<IActivityManager.ContentProviderHolder>();
|
||||
@ -3825,7 +3831,7 @@ public final class ActivityThread {
|
||||
}
|
||||
}
|
||||
|
||||
private final IContentProvider getExistingProvider(Context context, String name) {
|
||||
private IContentProvider getExistingProvider(Context context, String name) {
|
||||
synchronized(mProviderMap) {
|
||||
final ProviderClientRecord pr = mProviderMap.get(name);
|
||||
if (pr != null) {
|
||||
@ -3835,7 +3841,7 @@ public final class ActivityThread {
|
||||
}
|
||||
}
|
||||
|
||||
private final IContentProvider getProvider(Context context, String name) {
|
||||
private IContentProvider getProvider(Context context, String name) {
|
||||
IContentProvider existing = getExistingProvider(context, name);
|
||||
if (existing != null) {
|
||||
return existing;
|
||||
@ -4007,7 +4013,7 @@ public final class ActivityThread {
|
||||
}
|
||||
}
|
||||
|
||||
private final IContentProvider installProvider(Context context,
|
||||
private IContentProvider installProvider(Context context,
|
||||
IContentProvider provider, ProviderInfo info, boolean noisy) {
|
||||
ContentProvider localProvider = null;
|
||||
if (provider == null) {
|
||||
@ -4027,6 +4033,7 @@ public final class ActivityThread {
|
||||
c = context.createPackageContext(ai.packageName,
|
||||
Context.CONTEXT_INCLUDE_CODE);
|
||||
} catch (PackageManager.NameNotFoundException e) {
|
||||
// Ignore
|
||||
}
|
||||
}
|
||||
if (c == null) {
|
||||
@ -4086,7 +4093,7 @@ public final class ActivityThread {
|
||||
return provider;
|
||||
}
|
||||
|
||||
private final void attach(boolean system) {
|
||||
private void attach(boolean system) {
|
||||
sThreadLocal.set(this);
|
||||
mSystemThread = system;
|
||||
if (!system) {
|
||||
@ -4101,6 +4108,7 @@ public final class ActivityThread {
|
||||
try {
|
||||
mgr.attachApplication(mAppThread);
|
||||
} catch (RemoteException ex) {
|
||||
// Ignore
|
||||
}
|
||||
} else {
|
||||
// Don't set application object here -- if the system crashes,
|
||||
@ -4166,7 +4174,7 @@ public final class ActivityThread {
|
||||
}
|
||||
}
|
||||
|
||||
public static final void main(String[] args) {
|
||||
public static void main(String[] args) {
|
||||
SamplingProfilerIntegration.start();
|
||||
|
||||
// CloseGuard defaults to true and can be quite spammy. We
|
||||
|
@ -54,4 +54,11 @@ public abstract class DisplayList {
|
||||
* @return boolean true if the display list is able to be replayed, false otherwise.
|
||||
*/
|
||||
abstract boolean isValid();
|
||||
|
||||
/**
|
||||
* Return the amount of memory used by this display list.
|
||||
*
|
||||
* @return The size of this display list in bytes
|
||||
*/
|
||||
abstract int getSize();
|
||||
}
|
||||
|
@ -330,6 +330,12 @@ class GLES20Canvas extends HardwareCanvas {
|
||||
|
||||
private static native void nDestroyDisplayList(int displayList);
|
||||
|
||||
static int getDisplayListSize(int displayList) {
|
||||
return nGetDisplayListSize(displayList);
|
||||
}
|
||||
|
||||
private static native int nGetDisplayListSize(int displayList);
|
||||
|
||||
@Override
|
||||
public boolean drawDisplayList(DisplayList displayList, int width, int height, Rect dirty) {
|
||||
return nDrawDisplayList(mRenderer,
|
||||
|
@ -82,6 +82,12 @@ class GLES20DisplayList extends DisplayList {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
int getSize() {
|
||||
if (mFinalizer == null) return 0;
|
||||
return GLES20Canvas.getDisplayListSize(mFinalizer.mNativeDisplayList);
|
||||
}
|
||||
|
||||
private static class DisplayListFinalizer {
|
||||
final int mNativeDisplayList;
|
||||
|
||||
|
@ -934,7 +934,9 @@ public abstract class HardwareRenderer {
|
||||
}
|
||||
|
||||
private void destroyHardwareLayer(View view) {
|
||||
view.destroyLayer();
|
||||
if (view.destroyLayer()) {
|
||||
view.invalidate(true);
|
||||
}
|
||||
if (view instanceof ViewGroup) {
|
||||
ViewGroup group = (ViewGroup) view;
|
||||
|
||||
|
@ -2294,8 +2294,8 @@ public class View implements Drawable.Callback2, KeyEvent.Callback, Accessibilit
|
||||
|
||||
private Bitmap mDrawingCache;
|
||||
private Bitmap mUnscaledDrawingCache;
|
||||
private DisplayList mDisplayList;
|
||||
private HardwareLayer mHardwareLayer;
|
||||
DisplayList mDisplayList;
|
||||
|
||||
/**
|
||||
* When this view has focus and the next focus is {@link #FOCUS_LEFT},
|
||||
@ -9727,11 +9727,13 @@ public class View implements Drawable.Callback2, KeyEvent.Callback, Accessibilit
|
||||
return mHardwareLayer;
|
||||
}
|
||||
|
||||
void destroyLayer() {
|
||||
boolean destroyLayer() {
|
||||
if (mHardwareLayer != null) {
|
||||
mHardwareLayer.destroy();
|
||||
mHardwareLayer = null;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -420,7 +420,7 @@ public class ViewDebug {
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public static long getViewAncestorInstanceCount() {
|
||||
public static long getViewRootImplCount() {
|
||||
return Debug.countInstancesOfClass(ViewRootImpl.class);
|
||||
}
|
||||
|
||||
|
@ -80,6 +80,7 @@ import com.android.internal.view.RootViewSurfaceTaker;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.io.PrintWriter;
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
@ -235,7 +236,6 @@ public final class ViewRootImpl extends Handler implements ViewParent,
|
||||
final Configuration mLastConfiguration = new Configuration();
|
||||
final Configuration mPendingConfiguration = new Configuration();
|
||||
|
||||
|
||||
class ResizedInfo {
|
||||
Rect coveredInsets;
|
||||
Rect visibleInsets;
|
||||
@ -542,10 +542,26 @@ public final class ViewRootImpl extends Handler implements ViewParent,
|
||||
}
|
||||
|
||||
private void destroyHardwareResources() {
|
||||
if (mAttachInfo.mHardwareRenderer.isEnabled()) {
|
||||
mAttachInfo.mHardwareRenderer.destroyLayers(mView);
|
||||
if (mAttachInfo.mHardwareRenderer != null) {
|
||||
if (mAttachInfo.mHardwareRenderer.isEnabled()) {
|
||||
mAttachInfo.mHardwareRenderer.destroyLayers(mView);
|
||||
}
|
||||
mAttachInfo.mHardwareRenderer.destroy(false);
|
||||
}
|
||||
}
|
||||
|
||||
void destroyHardwareLayers() {
|
||||
if (mThread != Thread.currentThread()) {
|
||||
if (mAttachInfo.mHardwareRenderer != null &&
|
||||
mAttachInfo.mHardwareRenderer.isEnabled()) {
|
||||
HardwareRenderer.trimMemory(ComponentCallbacks.TRIM_MEMORY_MODERATE);
|
||||
}
|
||||
} else {
|
||||
if (mAttachInfo.mHardwareRenderer != null &&
|
||||
mAttachInfo.mHardwareRenderer.isEnabled()) {
|
||||
mAttachInfo.mHardwareRenderer.destroyLayers(mView);
|
||||
}
|
||||
}
|
||||
mAttachInfo.mHardwareRenderer.destroy(false);
|
||||
}
|
||||
|
||||
private void enableHardwareAcceleration(WindowManager.LayoutParams attrs) {
|
||||
@ -876,9 +892,7 @@ public final class ViewRootImpl extends Handler implements ViewParent,
|
||||
attachInfo.mWindowVisibility = viewVisibility;
|
||||
host.dispatchWindowVisibilityChanged(viewVisibility);
|
||||
if (viewVisibility != View.VISIBLE || mNewSurfaceNeeded) {
|
||||
if (mAttachInfo.mHardwareRenderer != null) {
|
||||
destroyHardwareResources();
|
||||
}
|
||||
destroyHardwareResources();
|
||||
}
|
||||
if (viewVisibility == View.GONE) {
|
||||
// After making a window gone, we will count it as being
|
||||
@ -3492,6 +3506,31 @@ public final class ViewRootImpl extends Handler implements ViewParent,
|
||||
public void debug() {
|
||||
mView.debug();
|
||||
}
|
||||
|
||||
public void dumpGfxInfo(PrintWriter pw, int[] info) {
|
||||
if (mView != null) {
|
||||
getGfxInfo(mView, info);
|
||||
} else {
|
||||
info[0] = info[1] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
private void getGfxInfo(View view, int[] info) {
|
||||
DisplayList displayList = view.mDisplayList;
|
||||
info[0]++;
|
||||
if (displayList != null) {
|
||||
info[1] += displayList.getSize();
|
||||
}
|
||||
|
||||
if (view instanceof ViewGroup) {
|
||||
ViewGroup group = (ViewGroup) view;
|
||||
|
||||
int count = group.getChildCount();
|
||||
for (int i = 0; i < count; i++) {
|
||||
getGfxInfo(group.getChildAt(i), info);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void die(boolean immediate) {
|
||||
if (immediate) {
|
||||
|
@ -24,6 +24,9 @@ import android.util.AndroidRuntimeException;
|
||||
import android.util.Log;
|
||||
import android.view.inputmethod.InputMethodManager;
|
||||
|
||||
import java.io.FileDescriptor;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.PrintWriter;
|
||||
import java.util.HashMap;
|
||||
|
||||
final class WindowLeaked extends AndroidRuntimeException {
|
||||
@ -392,7 +395,7 @@ public class WindowManagerImpl implements WindowManager {
|
||||
leak.setStackTrace(root.getLocation().getStackTrace());
|
||||
Log.e("WindowManager", leak.getMessage(), leak);
|
||||
}
|
||||
|
||||
|
||||
removeViewLocked(i);
|
||||
i--;
|
||||
count--;
|
||||
@ -410,6 +413,59 @@ public class WindowManagerImpl implements WindowManager {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public void trimLocalMemory() {
|
||||
synchronized (this) {
|
||||
if (mViews == null) return;
|
||||
int count = mViews.length;
|
||||
for (int i = 0; i < count; i++) {
|
||||
mRoots[i].destroyHardwareLayers();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public void dumpGfxInfo(FileDescriptor fd) {
|
||||
FileOutputStream fout = new FileOutputStream(fd);
|
||||
PrintWriter pw = new PrintWriter(fout);
|
||||
try {
|
||||
synchronized (this) {
|
||||
if (mViews != null) {
|
||||
pw.println("View hierarchy:");
|
||||
|
||||
final int count = mViews.length;
|
||||
|
||||
int viewsCount = 0;
|
||||
int displayListsSize = 0;
|
||||
int[] info = new int[2];
|
||||
|
||||
for (int i = 0; i < count; i++) {
|
||||
ViewRootImpl root = mRoots[i];
|
||||
root.dumpGfxInfo(pw, info);
|
||||
|
||||
String name = root.getClass().getName() + '@' +
|
||||
Integer.toHexString(hashCode());
|
||||
pw.printf(" %s: %d views, %.2f kB (display lists)\n",
|
||||
name, info[0], info[1] / 1024.0f);
|
||||
|
||||
viewsCount += info[0];
|
||||
displayListsSize += info[1];
|
||||
}
|
||||
|
||||
pw.printf("\nTotal ViewRootImpl: %d\n", count);
|
||||
pw.printf("Total Views: %d\n", viewsCount);
|
||||
pw.printf("Total DisplayList: %.2f kB\n\n", displayListsSize / 1024.0f);
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
pw.flush();
|
||||
}
|
||||
}
|
||||
|
||||
public void setStoppedState(IBinder token, boolean stopped) {
|
||||
synchronized (this) {
|
||||
if (mViews == null)
|
||||
|
@ -580,6 +580,11 @@ static DisplayList* android_view_GLES20Canvas_getDisplayList(JNIEnv* env,
|
||||
return renderer->getDisplayList(displayList);
|
||||
}
|
||||
|
||||
static jint android_view_GLES20Canvas_getDisplayListSize(JNIEnv* env,
|
||||
jobject clazz, DisplayList* displayList) {
|
||||
return displayList->getSize();
|
||||
}
|
||||
|
||||
static OpenGLRenderer* android_view_GLES20Canvas_createDisplayListRenderer(JNIEnv* env,
|
||||
jobject clazz) {
|
||||
return new DisplayListRenderer;
|
||||
@ -721,8 +726,7 @@ static jboolean android_view_GLES20Canvas_isAvailable(JNIEnv* env, jobject clazz
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
static void
|
||||
android_app_ActivityThread_dumpGraphics(JNIEnv* env, jobject clazz, jobject javaFileDescriptor)
|
||||
{
|
||||
android_app_ActivityThread_dumpGraphics(JNIEnv* env, jobject clazz, jobject javaFileDescriptor) {
|
||||
#ifdef USE_OPENGL_RENDERER
|
||||
int fd = jniGetFDFromFileDescriptor(env, javaFileDescriptor);
|
||||
android::uirenderer::DisplayList::outputLogBuffer(fd);
|
||||
@ -814,6 +818,7 @@ static JNINativeMethod gMethods[] = {
|
||||
|
||||
{ "nGetDisplayList", "(II)I", (void*) android_view_GLES20Canvas_getDisplayList },
|
||||
{ "nDestroyDisplayList", "(I)V", (void*) android_view_GLES20Canvas_destroyDisplayList },
|
||||
{ "nGetDisplayListSize", "(I)I", (void*) android_view_GLES20Canvas_getDisplayListSize },
|
||||
{ "nCreateDisplayListRenderer", "()I", (void*) android_view_GLES20Canvas_createDisplayListRenderer },
|
||||
{ "nResetDisplayListRenderer", "(I)V", (void*) android_view_GLES20Canvas_resetDisplayListRenderer },
|
||||
{ "nDrawDisplayList", "(IIIILandroid/graphics/Rect;)Z",
|
||||
|
@ -74,12 +74,17 @@ void DisplayList::outputLogBuffer(int fd) {
|
||||
if (logBuffer.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
String8 cachesLog;
|
||||
Caches::getInstance().dumpMemoryUsage(cachesLog);
|
||||
|
||||
FILE *file = fdopen(fd, "a");
|
||||
fprintf(file, "\nCaches:\n%s", cachesLog.string());
|
||||
|
||||
fprintf(file, "\nRecent DisplayList operations\n");
|
||||
logBuffer.outputCommands(file, OP_NAMES);
|
||||
|
||||
String8 cachesLog;
|
||||
Caches::getInstance().dumpMemoryUsage(cachesLog);
|
||||
fprintf(file, "\nCaches:\n%s", cachesLog.string());
|
||||
fprintf(file, "\n");
|
||||
|
||||
fflush(file);
|
||||
}
|
||||
|
||||
@ -143,10 +148,10 @@ void DisplayList::initFromDisplayListRenderer(const DisplayListRenderer& recorde
|
||||
clearResources();
|
||||
}
|
||||
|
||||
size_t size = writer.size();
|
||||
void* buffer = sk_malloc_throw(size);
|
||||
mSize = writer.size();
|
||||
void* buffer = sk_malloc_throw(mSize);
|
||||
writer.flatten(buffer);
|
||||
mReader.setMemory(buffer, size);
|
||||
mReader.setMemory(buffer, mSize);
|
||||
|
||||
Caches& caches = Caches::getInstance();
|
||||
|
||||
@ -188,6 +193,11 @@ void DisplayList::initFromDisplayListRenderer(const DisplayListRenderer& recorde
|
||||
}
|
||||
|
||||
void DisplayList::init() {
|
||||
mSize = 0;
|
||||
}
|
||||
|
||||
size_t DisplayList::getSize() {
|
||||
return mSize;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -105,6 +105,8 @@ public:
|
||||
|
||||
void initFromDisplayListRenderer(const DisplayListRenderer& recorder, bool reusing = false);
|
||||
|
||||
size_t getSize();
|
||||
|
||||
bool replay(OpenGLRenderer& renderer, Rect& dirty, uint32_t level = 0);
|
||||
|
||||
void output(OpenGLRenderer& renderer, uint32_t level = 0);
|
||||
@ -203,6 +205,8 @@ private:
|
||||
Vector<SkiaShader*> mShaders;
|
||||
|
||||
mutable SkFlattenableReadBuffer mReader;
|
||||
|
||||
size_t mSize;
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -68,6 +68,7 @@ void LayerCache::setMaxSize(uint32_t maxSize) {
|
||||
|
||||
void LayerCache::deleteLayer(Layer* layer) {
|
||||
if (layer) {
|
||||
LAYER_LOGD("Destroying layer %dx%d", layer->getWidth(), layer->getHeight());
|
||||
mSize -= layer->getWidth() * layer->getHeight() * 4;
|
||||
layer->deleteFbo();
|
||||
layer->deleteTexture();
|
||||
|
@ -301,7 +301,7 @@ void LayerRenderer::destroyLayer(Layer* layer) {
|
||||
delete layer;
|
||||
} else {
|
||||
LAYER_RENDERER_LOGD(" Cached!");
|
||||
#if DEBUG_LAYERS
|
||||
#if DEBUG_LAYER_RENDERER
|
||||
Caches::getInstance().layerCache.dump();
|
||||
#endif
|
||||
layer->region.clear();
|
||||
|
@ -68,7 +68,7 @@ enum DebugLevel {
|
||||
#define MB(s) s * 1024 * 1024
|
||||
|
||||
#define DEFAULT_TEXTURE_CACHE_SIZE 24.0f
|
||||
#define DEFAULT_LAYER_CACHE_SIZE 24.0f
|
||||
#define DEFAULT_LAYER_CACHE_SIZE 16.0f
|
||||
#define DEFAULT_PATH_CACHE_SIZE 4.0f
|
||||
#define DEFAULT_SHAPE_CACHE_SIZE 1.0f
|
||||
#define DEFAULT_PATCH_CACHE_SIZE 512
|
||||
|
Reference in New Issue
Block a user