Loading core/java/com/android/internal/os/BinderInternal.java +108 −0 Original line number Diff line number Diff line Loading @@ -23,6 +23,14 @@ import android.util.EventLog; import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.FutureTask; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; import java.lang.Object; /** * Private and debugging Binder APIs. * Loading @@ -34,6 +42,13 @@ public class BinderInternal { static ArrayList<Runnable> sGcWatchers = new ArrayList<>(); static Runnable[] sTmpWatchers = new Runnable[1]; static long sLastGcTime; /* Maximum duration a GC can be delayed. */ private static final int GC_DELAY_MAX_DURATION = 3000; /** * Maximum number of times a GC can be delayed since the * original request. */ private static final int POSTPONED_GC_MAX = 5; static final class GcWatcher { @Override Loading Loading @@ -99,7 +114,100 @@ public class BinderInternal { Runtime.getRuntime().gc(); } /** * TimerGc Callable : Wait for a certain time, and execute the BinderGc. * Set the postponed count to 0. */ public static class TimerGc implements Callable<Void> { private long waitTime; public TimerGc(long timeInMillis){ this.waitTime=timeInMillis; } @Override public Void call() throws Exception { Thread.sleep(waitTime); forceGc("Binder"); postponedGcCount = 0; return null; } } /** * lastGcDelayRequestTime records the time-stamp of the last time * a GC delay request was made. */ static long lastGcDelayRequestTime = SystemClock.uptimeMillis(); static TimerGc timerGcInstance = null ; static FutureTask<Void> futureTaskInstance = null ; static ExecutorService executor = Executors.newFixedThreadPool(1); static int postponedGcCount = 0; static Object delayGcMonitorObject = new Object(); /** * modifyDelayedGcParams : Call from the framework based on some special Ux event. * like appLaunch. * * 1. If this is the first time for the trigger event, or, if there is no scheduled * task, create a new FutureTaskInstance, and set the lastGcDelayRequestTime. * This will be used by forceBinderGc later. * * 2. If the postponed iterations hit a maximum limit, do nothing. Let the current * task execute the gc. If not, * * a. Set the start time. * b. Increment the postponed count * c. Cancel the current task and start a new one for GC_DELAY_MAX_DURATION. */ public static void modifyDelayedGcParams() { long nowTime = SystemClock.uptimeMillis(); synchronized(delayGcMonitorObject) { if ((futureTaskInstance != null) && (postponedGcCount != 0)) { if (postponedGcCount <= POSTPONED_GC_MAX) { futureTaskInstance.cancel(true); if (futureTaskInstance.isCancelled()) { lastGcDelayRequestTime = nowTime; postponedGcCount++; timerGcInstance = new TimerGc(GC_DELAY_MAX_DURATION); futureTaskInstance = new FutureTask<Void>(timerGcInstance); executor.execute(futureTaskInstance); } } } else { lastGcDelayRequestTime = nowTime; timerGcInstance = new TimerGc(GC_DELAY_MAX_DURATION); futureTaskInstance = new FutureTask<Void>(timerGcInstance); } } } /** * Modified forceBinderGc. The brief algorithm is as follows -- * * 1. If no futureTaskInstance has been initiated, directly force a BinderGc. * 2. Check for the duration since the last request, and see if it was within the * last GC_DELAY_MAX_DURATION secs. If yes, we need to delay the GC until * GC_DELAY_MAX_DURATION. * 3. If there is a task scheduled (postponedGcCount != 0), we merely prevent this GC, * and let the GC scheduled execute. * 4. If no task is scheduled, we schedule one now for (GC_DELAY_MAX_DURATION - touch duration), * and update postponedGcCount. */ static void forceBinderGc() { synchronized(delayGcMonitorObject) { if (futureTaskInstance != null) { long lastGcDelayRequestDuration = (SystemClock.uptimeMillis() - lastGcDelayRequestTime); if (lastGcDelayRequestDuration < GC_DELAY_MAX_DURATION) { if (postponedGcCount != 0) return; futureTaskInstance.cancel(true); timerGcInstance = new TimerGc(GC_DELAY_MAX_DURATION - lastGcDelayRequestDuration); futureTaskInstance = new FutureTask<Void>(timerGcInstance); postponedGcCount = 1; executor.execute(futureTaskInstance); return; } } } forceGc("Binder"); } } services/core/java/com/android/server/am/ActivityStackSupervisor.java +3 −0 Original line number Diff line number Diff line Loading @@ -103,6 +103,7 @@ import com.android.internal.widget.LockPatternUtils; import com.android.server.LocalServices; import com.android.server.am.ActivityStack.ActivityState; import com.android.server.wm.WindowManagerService; import com.android.internal.os.BinderInternal; import java.io.FileDescriptor; Loading Loading @@ -2665,6 +2666,8 @@ public final class ActivityStackSupervisor implements DisplayListener { mPerf.perfLockAcquire(lBoostTimeOut, lBoostPcDisblBoost, lBoostSchedBoost, lBoostCpuBoost, lBoostKsmBoost); } /* Delay Binder Explicit GC during application launch */ BinderInternal.modifyDelayedGcParams(); if (DEBUG_TASKS) Slog.d(TAG, "No task found"); return null; Loading Loading
core/java/com/android/internal/os/BinderInternal.java +108 −0 Original line number Diff line number Diff line Loading @@ -23,6 +23,14 @@ import android.util.EventLog; import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.FutureTask; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; import java.lang.Object; /** * Private and debugging Binder APIs. * Loading @@ -34,6 +42,13 @@ public class BinderInternal { static ArrayList<Runnable> sGcWatchers = new ArrayList<>(); static Runnable[] sTmpWatchers = new Runnable[1]; static long sLastGcTime; /* Maximum duration a GC can be delayed. */ private static final int GC_DELAY_MAX_DURATION = 3000; /** * Maximum number of times a GC can be delayed since the * original request. */ private static final int POSTPONED_GC_MAX = 5; static final class GcWatcher { @Override Loading Loading @@ -99,7 +114,100 @@ public class BinderInternal { Runtime.getRuntime().gc(); } /** * TimerGc Callable : Wait for a certain time, and execute the BinderGc. * Set the postponed count to 0. */ public static class TimerGc implements Callable<Void> { private long waitTime; public TimerGc(long timeInMillis){ this.waitTime=timeInMillis; } @Override public Void call() throws Exception { Thread.sleep(waitTime); forceGc("Binder"); postponedGcCount = 0; return null; } } /** * lastGcDelayRequestTime records the time-stamp of the last time * a GC delay request was made. */ static long lastGcDelayRequestTime = SystemClock.uptimeMillis(); static TimerGc timerGcInstance = null ; static FutureTask<Void> futureTaskInstance = null ; static ExecutorService executor = Executors.newFixedThreadPool(1); static int postponedGcCount = 0; static Object delayGcMonitorObject = new Object(); /** * modifyDelayedGcParams : Call from the framework based on some special Ux event. * like appLaunch. * * 1. If this is the first time for the trigger event, or, if there is no scheduled * task, create a new FutureTaskInstance, and set the lastGcDelayRequestTime. * This will be used by forceBinderGc later. * * 2. If the postponed iterations hit a maximum limit, do nothing. Let the current * task execute the gc. If not, * * a. Set the start time. * b. Increment the postponed count * c. Cancel the current task and start a new one for GC_DELAY_MAX_DURATION. */ public static void modifyDelayedGcParams() { long nowTime = SystemClock.uptimeMillis(); synchronized(delayGcMonitorObject) { if ((futureTaskInstance != null) && (postponedGcCount != 0)) { if (postponedGcCount <= POSTPONED_GC_MAX) { futureTaskInstance.cancel(true); if (futureTaskInstance.isCancelled()) { lastGcDelayRequestTime = nowTime; postponedGcCount++; timerGcInstance = new TimerGc(GC_DELAY_MAX_DURATION); futureTaskInstance = new FutureTask<Void>(timerGcInstance); executor.execute(futureTaskInstance); } } } else { lastGcDelayRequestTime = nowTime; timerGcInstance = new TimerGc(GC_DELAY_MAX_DURATION); futureTaskInstance = new FutureTask<Void>(timerGcInstance); } } } /** * Modified forceBinderGc. The brief algorithm is as follows -- * * 1. If no futureTaskInstance has been initiated, directly force a BinderGc. * 2. Check for the duration since the last request, and see if it was within the * last GC_DELAY_MAX_DURATION secs. If yes, we need to delay the GC until * GC_DELAY_MAX_DURATION. * 3. If there is a task scheduled (postponedGcCount != 0), we merely prevent this GC, * and let the GC scheduled execute. * 4. If no task is scheduled, we schedule one now for (GC_DELAY_MAX_DURATION - touch duration), * and update postponedGcCount. */ static void forceBinderGc() { synchronized(delayGcMonitorObject) { if (futureTaskInstance != null) { long lastGcDelayRequestDuration = (SystemClock.uptimeMillis() - lastGcDelayRequestTime); if (lastGcDelayRequestDuration < GC_DELAY_MAX_DURATION) { if (postponedGcCount != 0) return; futureTaskInstance.cancel(true); timerGcInstance = new TimerGc(GC_DELAY_MAX_DURATION - lastGcDelayRequestDuration); futureTaskInstance = new FutureTask<Void>(timerGcInstance); postponedGcCount = 1; executor.execute(futureTaskInstance); return; } } } forceGc("Binder"); } }
services/core/java/com/android/server/am/ActivityStackSupervisor.java +3 −0 Original line number Diff line number Diff line Loading @@ -103,6 +103,7 @@ import com.android.internal.widget.LockPatternUtils; import com.android.server.LocalServices; import com.android.server.am.ActivityStack.ActivityState; import com.android.server.wm.WindowManagerService; import com.android.internal.os.BinderInternal; import java.io.FileDescriptor; Loading Loading @@ -2665,6 +2666,8 @@ public final class ActivityStackSupervisor implements DisplayListener { mPerf.perfLockAcquire(lBoostTimeOut, lBoostPcDisblBoost, lBoostSchedBoost, lBoostCpuBoost, lBoostKsmBoost); } /* Delay Binder Explicit GC during application launch */ BinderInternal.modifyDelayedGcParams(); if (DEBUG_TASKS) Slog.d(TAG, "No task found"); return null; Loading