Merge "Layer "locked" methods for better locking logs." into udc-dev
This commit is contained in:
@@ -1050,13 +1050,13 @@ class BroadcastProcessQueue {
|
|||||||
* Check overall health, confirming things are in a reasonable state and
|
* Check overall health, confirming things are in a reasonable state and
|
||||||
* that we're not wedged.
|
* that we're not wedged.
|
||||||
*/
|
*/
|
||||||
public void checkHealthLocked() {
|
public void assertHealthLocked() {
|
||||||
checkHealthLocked(mPending);
|
assertHealthLocked(mPending);
|
||||||
checkHealthLocked(mPendingUrgent);
|
assertHealthLocked(mPendingUrgent);
|
||||||
checkHealthLocked(mPendingOffload);
|
assertHealthLocked(mPendingOffload);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void checkHealthLocked(@NonNull ArrayDeque<SomeArgs> queue) {
|
private void assertHealthLocked(@NonNull ArrayDeque<SomeArgs> queue) {
|
||||||
if (queue.isEmpty()) return;
|
if (queue.isEmpty()) return;
|
||||||
|
|
||||||
final Iterator<SomeArgs> it = queue.descendingIterator();
|
final Iterator<SomeArgs> it = queue.descendingIterator();
|
||||||
|
|||||||
@@ -246,21 +246,15 @@ class BroadcastQueueModernImpl extends BroadcastQueue {
|
|||||||
private final Handler.Callback mLocalCallback = (msg) -> {
|
private final Handler.Callback mLocalCallback = (msg) -> {
|
||||||
switch (msg.what) {
|
switch (msg.what) {
|
||||||
case MSG_UPDATE_RUNNING_LIST: {
|
case MSG_UPDATE_RUNNING_LIST: {
|
||||||
synchronized (mService) {
|
updateRunningList();
|
||||||
updateRunningListLocked();
|
|
||||||
}
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
case MSG_DELIVERY_TIMEOUT_SOFT: {
|
case MSG_DELIVERY_TIMEOUT_SOFT: {
|
||||||
synchronized (mService) {
|
deliveryTimeoutSoft((BroadcastProcessQueue) msg.obj, msg.arg1);
|
||||||
deliveryTimeoutSoftLocked((BroadcastProcessQueue) msg.obj, msg.arg1);
|
|
||||||
}
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
case MSG_DELIVERY_TIMEOUT_HARD: {
|
case MSG_DELIVERY_TIMEOUT_HARD: {
|
||||||
synchronized (mService) {
|
deliveryTimeoutHard((BroadcastProcessQueue) msg.obj);
|
||||||
deliveryTimeoutHardLocked((BroadcastProcessQueue) msg.obj);
|
|
||||||
}
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
case MSG_BG_ACTIVITY_START_TIMEOUT: {
|
case MSG_BG_ACTIVITY_START_TIMEOUT: {
|
||||||
@@ -274,9 +268,7 @@ class BroadcastQueueModernImpl extends BroadcastQueue {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
case MSG_CHECK_HEALTH: {
|
case MSG_CHECK_HEALTH: {
|
||||||
synchronized (mService) {
|
checkHealth();
|
||||||
checkHealthLocked();
|
|
||||||
}
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -365,6 +357,12 @@ class BroadcastQueueModernImpl extends BroadcastQueue {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void updateRunningList() {
|
||||||
|
synchronized (mService) {
|
||||||
|
updateRunningListLocked();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Consider updating the list of "running" queues.
|
* Consider updating the list of "running" queues.
|
||||||
* <p>
|
* <p>
|
||||||
@@ -965,6 +963,13 @@ class BroadcastQueueModernImpl extends BroadcastQueue {
|
|||||||
r.resultTo = null;
|
r.resultTo = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void deliveryTimeoutSoft(@NonNull BroadcastProcessQueue queue,
|
||||||
|
int softTimeoutMillis) {
|
||||||
|
synchronized (mService) {
|
||||||
|
deliveryTimeoutSoftLocked(queue, softTimeoutMillis);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void deliveryTimeoutSoftLocked(@NonNull BroadcastProcessQueue queue,
|
private void deliveryTimeoutSoftLocked(@NonNull BroadcastProcessQueue queue,
|
||||||
int softTimeoutMillis) {
|
int softTimeoutMillis) {
|
||||||
if (queue.app != null) {
|
if (queue.app != null) {
|
||||||
@@ -981,6 +986,12 @@ class BroadcastQueueModernImpl extends BroadcastQueue {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void deliveryTimeoutHard(@NonNull BroadcastProcessQueue queue) {
|
||||||
|
synchronized (mService) {
|
||||||
|
deliveryTimeoutHardLocked(queue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void deliveryTimeoutHardLocked(@NonNull BroadcastProcessQueue queue) {
|
private void deliveryTimeoutHardLocked(@NonNull BroadcastProcessQueue queue) {
|
||||||
finishReceiverActiveLocked(queue, BroadcastRecord.DELIVERY_TIMEOUT,
|
finishReceiverActiveLocked(queue, BroadcastRecord.DELIVERY_TIMEOUT,
|
||||||
"deliveryTimeoutHardLocked");
|
"deliveryTimeoutHardLocked");
|
||||||
@@ -1458,52 +1469,19 @@ class BroadcastQueueModernImpl extends BroadcastQueue {
|
|||||||
// TODO: implement
|
// TODO: implement
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
private void checkHealth() {
|
||||||
* Check overall health, confirming things are in a reasonable state and
|
synchronized (mService) {
|
||||||
* that we're not wedged. If we determine we're in an unhealthy state, dump
|
checkHealthLocked();
|
||||||
* current state once and stop future health checks to avoid spamming.
|
}
|
||||||
*/
|
}
|
||||||
@VisibleForTesting
|
|
||||||
void checkHealthLocked() {
|
private void checkHealthLocked() {
|
||||||
try {
|
try {
|
||||||
// Verify all runnable queues are sorted
|
assertHealthLocked();
|
||||||
BroadcastProcessQueue prev = null;
|
|
||||||
BroadcastProcessQueue next = mRunnableHead;
|
|
||||||
while (next != null) {
|
|
||||||
checkState(next.runnableAtPrev == prev, "runnableAtPrev");
|
|
||||||
checkState(next.isRunnable(), "isRunnable " + next);
|
|
||||||
if (prev != null) {
|
|
||||||
checkState(next.getRunnableAt() >= prev.getRunnableAt(),
|
|
||||||
"getRunnableAt " + next + " vs " + prev);
|
|
||||||
}
|
|
||||||
prev = next;
|
|
||||||
next = next.runnableAtNext;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Verify all running queues are active
|
|
||||||
for (BroadcastProcessQueue queue : mRunning) {
|
|
||||||
if (queue != null) {
|
|
||||||
checkState(queue.isActive(), "isActive " + queue);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Verify that pending cold start hasn't been orphaned
|
|
||||||
if (mRunningColdStart != null) {
|
|
||||||
checkState(getRunningIndexOf(mRunningColdStart) >= 0,
|
|
||||||
"isOrphaned " + mRunningColdStart);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Verify health of all known process queues
|
|
||||||
for (int i = 0; i < mProcessQueues.size(); i++) {
|
|
||||||
BroadcastProcessQueue leaf = mProcessQueues.valueAt(i);
|
|
||||||
while (leaf != null) {
|
|
||||||
leaf.checkHealthLocked();
|
|
||||||
leaf = leaf.processNameNext;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// If no health issues found above, check again in the future
|
// If no health issues found above, check again in the future
|
||||||
mLocalHandler.sendEmptyMessageDelayed(MSG_CHECK_HEALTH, DateUtils.MINUTE_IN_MILLIS);
|
mLocalHandler.sendEmptyMessageDelayed(MSG_CHECK_HEALTH,
|
||||||
|
DateUtils.MINUTE_IN_MILLIS);
|
||||||
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
// Throw up a message to indicate that something went wrong, and
|
// Throw up a message to indicate that something went wrong, and
|
||||||
@@ -1513,6 +1491,50 @@ class BroadcastQueueModernImpl extends BroadcastQueue {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check overall health, confirming things are in a reasonable state and
|
||||||
|
* that we're not wedged. If we determine we're in an unhealthy state, dump
|
||||||
|
* current state once and stop future health checks to avoid spamming.
|
||||||
|
*/
|
||||||
|
@VisibleForTesting
|
||||||
|
void assertHealthLocked() {
|
||||||
|
// Verify all runnable queues are sorted
|
||||||
|
BroadcastProcessQueue prev = null;
|
||||||
|
BroadcastProcessQueue next = mRunnableHead;
|
||||||
|
while (next != null) {
|
||||||
|
checkState(next.runnableAtPrev == prev, "runnableAtPrev");
|
||||||
|
checkState(next.isRunnable(), "isRunnable " + next);
|
||||||
|
if (prev != null) {
|
||||||
|
checkState(next.getRunnableAt() >= prev.getRunnableAt(),
|
||||||
|
"getRunnableAt " + next + " vs " + prev);
|
||||||
|
}
|
||||||
|
prev = next;
|
||||||
|
next = next.runnableAtNext;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify all running queues are active
|
||||||
|
for (BroadcastProcessQueue queue : mRunning) {
|
||||||
|
if (queue != null) {
|
||||||
|
checkState(queue.isActive(), "isActive " + queue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify that pending cold start hasn't been orphaned
|
||||||
|
if (mRunningColdStart != null) {
|
||||||
|
checkState(getRunningIndexOf(mRunningColdStart) >= 0,
|
||||||
|
"isOrphaned " + mRunningColdStart);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify health of all known process queues
|
||||||
|
for (int i = 0; i < mProcessQueues.size(); i++) {
|
||||||
|
BroadcastProcessQueue leaf = mProcessQueues.valueAt(i);
|
||||||
|
while (leaf != null) {
|
||||||
|
leaf.assertHealthLocked();
|
||||||
|
leaf = leaf.processNameNext;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void updateWarmProcess(@NonNull BroadcastProcessQueue queue) {
|
private void updateWarmProcess(@NonNull BroadcastProcessQueue queue) {
|
||||||
if (!queue.isProcessWarm()) {
|
if (!queue.isProcessWarm()) {
|
||||||
setQueueProcess(queue, mService.getProcessRecordLocked(queue.processName, queue.uid));
|
setQueueProcess(queue, mService.getProcessRecordLocked(queue.processName, queue.uid));
|
||||||
|
|||||||
@@ -91,8 +91,8 @@ import org.junit.Rule;
|
|||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.mockito.Mock;
|
import org.mockito.Mock;
|
||||||
|
|
||||||
import java.io.ByteArrayOutputStream;
|
|
||||||
import java.io.PrintWriter;
|
import java.io.PrintWriter;
|
||||||
|
import java.io.Writer;
|
||||||
import java.lang.reflect.Array;
|
import java.lang.reflect.Array;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -596,7 +596,7 @@ public final class BroadcastQueueModernImplTest {
|
|||||||
// about the actual output, just that we don't crash
|
// about the actual output, just that we don't crash
|
||||||
queue.getActive().setDeliveryState(0, BroadcastRecord.DELIVERY_SCHEDULED, "Test-driven");
|
queue.getActive().setDeliveryState(0, BroadcastRecord.DELIVERY_SCHEDULED, "Test-driven");
|
||||||
queue.dumpLocked(SystemClock.uptimeMillis(),
|
queue.dumpLocked(SystemClock.uptimeMillis(),
|
||||||
new IndentingPrintWriter(new PrintWriter(new ByteArrayOutputStream())));
|
new IndentingPrintWriter(new PrintWriter(Writer.nullWriter())));
|
||||||
|
|
||||||
queue.makeActiveNextPending();
|
queue.makeActiveNextPending();
|
||||||
assertEquals(Intent.ACTION_LOCALE_CHANGED, queue.getActive().intent.getAction());
|
assertEquals(Intent.ACTION_LOCALE_CHANGED, queue.getActive().intent.getAction());
|
||||||
@@ -1166,6 +1166,11 @@ public final class BroadcastQueueModernImplTest {
|
|||||||
List<Intent> intents) {
|
List<Intent> intents) {
|
||||||
for (int i = 0; i < intents.size(); i++) {
|
for (int i = 0; i < intents.size(); i++) {
|
||||||
queue.makeActiveNextPending();
|
queue.makeActiveNextPending();
|
||||||
|
|
||||||
|
// While we're here, give our health check some test coverage
|
||||||
|
queue.assertHealthLocked();
|
||||||
|
queue.dumpLocked(0L, new IndentingPrintWriter(Writer.nullWriter()));
|
||||||
|
|
||||||
final Intent actualIntent = queue.getActive().intent;
|
final Intent actualIntent = queue.getActive().intent;
|
||||||
final Intent expectedIntent = intents.get(i);
|
final Intent expectedIntent = intents.get(i);
|
||||||
final String errMsg = "actual=" + actualIntent + ", expected=" + expectedIntent
|
final String errMsg = "actual=" + actualIntent + ", expected=" + expectedIntent
|
||||||
|
|||||||
@@ -39,6 +39,7 @@ import static org.mockito.Mockito.atLeastOnce;
|
|||||||
import static org.mockito.Mockito.doAnswer;
|
import static org.mockito.Mockito.doAnswer;
|
||||||
import static org.mockito.Mockito.doNothing;
|
import static org.mockito.Mockito.doNothing;
|
||||||
import static org.mockito.Mockito.doReturn;
|
import static org.mockito.Mockito.doReturn;
|
||||||
|
import static org.mockito.Mockito.doThrow;
|
||||||
import static org.mockito.Mockito.inOrder;
|
import static org.mockito.Mockito.inOrder;
|
||||||
import static org.mockito.Mockito.mock;
|
import static org.mockito.Mockito.mock;
|
||||||
import static org.mockito.Mockito.never;
|
import static org.mockito.Mockito.never;
|
||||||
@@ -106,10 +107,10 @@ import org.mockito.Mock;
|
|||||||
import org.mockito.MockitoAnnotations;
|
import org.mockito.MockitoAnnotations;
|
||||||
import org.mockito.verification.VerificationMode;
|
import org.mockito.verification.VerificationMode;
|
||||||
|
|
||||||
import java.io.ByteArrayOutputStream;
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileDescriptor;
|
import java.io.FileDescriptor;
|
||||||
import java.io.PrintWriter;
|
import java.io.PrintWriter;
|
||||||
|
import java.io.Writer;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
@@ -231,6 +232,7 @@ public class BroadcastQueueTest {
|
|||||||
doAnswer((invocation) -> {
|
doAnswer((invocation) -> {
|
||||||
Log.v(TAG, "Intercepting startProcessLocked() for "
|
Log.v(TAG, "Intercepting startProcessLocked() for "
|
||||||
+ Arrays.toString(invocation.getArguments()));
|
+ Arrays.toString(invocation.getArguments()));
|
||||||
|
assertHealth();
|
||||||
final ProcessStartBehavior behavior = mNextProcessStartBehavior
|
final ProcessStartBehavior behavior = mNextProcessStartBehavior
|
||||||
.getAndSet(ProcessStartBehavior.SUCCESS);
|
.getAndSet(ProcessStartBehavior.SUCCESS);
|
||||||
if (behavior == ProcessStartBehavior.FAIL_NULL) {
|
if (behavior == ProcessStartBehavior.FAIL_NULL) {
|
||||||
@@ -462,6 +464,7 @@ public class BroadcastQueueTest {
|
|||||||
doAnswer((invocation) -> {
|
doAnswer((invocation) -> {
|
||||||
Log.v(TAG, "Intercepting scheduleReceiver() for "
|
Log.v(TAG, "Intercepting scheduleReceiver() for "
|
||||||
+ Arrays.toString(invocation.getArguments()));
|
+ Arrays.toString(invocation.getArguments()));
|
||||||
|
assertHealth();
|
||||||
final Intent intent = invocation.getArgument(0);
|
final Intent intent = invocation.getArgument(0);
|
||||||
final Bundle extras = invocation.getArgument(5);
|
final Bundle extras = invocation.getArgument(5);
|
||||||
mScheduledBroadcasts.add(makeScheduledBroadcast(r, intent));
|
mScheduledBroadcasts.add(makeScheduledBroadcast(r, intent));
|
||||||
@@ -483,6 +486,7 @@ public class BroadcastQueueTest {
|
|||||||
doAnswer((invocation) -> {
|
doAnswer((invocation) -> {
|
||||||
Log.v(TAG, "Intercepting scheduleRegisteredReceiver() for "
|
Log.v(TAG, "Intercepting scheduleRegisteredReceiver() for "
|
||||||
+ Arrays.toString(invocation.getArguments()));
|
+ Arrays.toString(invocation.getArguments()));
|
||||||
|
assertHealth();
|
||||||
final Intent intent = invocation.getArgument(1);
|
final Intent intent = invocation.getArgument(1);
|
||||||
final Bundle extras = invocation.getArgument(4);
|
final Bundle extras = invocation.getArgument(4);
|
||||||
final boolean ordered = invocation.getArgument(5);
|
final boolean ordered = invocation.getArgument(5);
|
||||||
@@ -600,6 +604,13 @@ public class BroadcastQueueTest {
|
|||||||
BackgroundStartPrivileges.NONE, false, null);
|
BackgroundStartPrivileges.NONE, false, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void assertHealth() {
|
||||||
|
if (mImpl == Impl.MODERN) {
|
||||||
|
// If this fails, it'll throw a clear reason message
|
||||||
|
((BroadcastQueueModernImpl) mQueue).assertHealthLocked();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private static Map<String, Object> asMap(Bundle bundle) {
|
private static Map<String, Object> asMap(Bundle bundle) {
|
||||||
final Map<String, Object> map = new HashMap<>();
|
final Map<String, Object> map = new HashMap<>();
|
||||||
if (bundle != null) {
|
if (bundle != null) {
|
||||||
@@ -769,7 +780,7 @@ public class BroadcastQueueTest {
|
|||||||
// about the actual output, just that we don't crash
|
// about the actual output, just that we don't crash
|
||||||
mQueue.dumpDebug(new ProtoOutputStream(),
|
mQueue.dumpDebug(new ProtoOutputStream(),
|
||||||
ActivityManagerServiceDumpBroadcastsProto.BROADCAST_QUEUE);
|
ActivityManagerServiceDumpBroadcastsProto.BROADCAST_QUEUE);
|
||||||
mQueue.dumpLocked(FileDescriptor.err, new PrintWriter(new ByteArrayOutputStream()),
|
mQueue.dumpLocked(FileDescriptor.err, new PrintWriter(Writer.nullWriter()),
|
||||||
null, 0, true, true, true, null, false);
|
null, 0, true, true, true, null, false);
|
||||||
mQueue.dumpToDropBoxLocked(TAG);
|
mQueue.dumpToDropBoxLocked(TAG);
|
||||||
|
|
||||||
@@ -1166,7 +1177,7 @@ public class BroadcastQueueTest {
|
|||||||
// about the actual output, just that we don't crash
|
// about the actual output, just that we don't crash
|
||||||
mQueue.dumpDebug(new ProtoOutputStream(),
|
mQueue.dumpDebug(new ProtoOutputStream(),
|
||||||
ActivityManagerServiceDumpBroadcastsProto.BROADCAST_QUEUE);
|
ActivityManagerServiceDumpBroadcastsProto.BROADCAST_QUEUE);
|
||||||
mQueue.dumpLocked(FileDescriptor.err, new PrintWriter(new ByteArrayOutputStream()),
|
mQueue.dumpLocked(FileDescriptor.err, new PrintWriter(Writer.nullWriter()),
|
||||||
null, 0, true, true, true, null, false);
|
null, 0, true, true, true, null, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user