Skip to content

Commit

Permalink
Use Throwable.addSuppressed in the Android copy of ServiceManager.
Browse files Browse the repository at this point in the history
It was [added in API Level 19](https://developer.android.com/reference/java/lang/Throwable#addSuppressed(java.lang.Throwable)), so we can rely on it.

Also, address an `IdentityHashMapUsage` warning, and migrate off `newIdentityHashMap`.

RELNOTES=n/a
PiperOrigin-RevId: 631389682
  • Loading branch information
cpovirk authored and Google Java Core Libraries committed May 7, 2024
1 parent 381835d commit 61d3f25
Show file tree
Hide file tree
Showing 2 changed files with 22 additions and 4 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,8 @@
import java.lang.ref.WeakReference;
import java.util.Collections;
import java.util.EnumSet;
import java.util.IdentityHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.Executor;
import java.util.concurrent.TimeUnit;
Expand Down Expand Up @@ -409,7 +409,7 @@ private static final class ServiceManagerState {
final Multiset<State> states = servicesByState.keys();

@GuardedBy("monitor")
final Map<Service, Stopwatch> startupTimers = Maps.newIdentityHashMap();
final IdentityHashMap<Service, Stopwatch> startupTimers = new IdentityHashMap<>();

/**
* These two booleans are used to mark the state as ready to start.
Expand Down Expand Up @@ -725,6 +725,9 @@ void checkHealthy() {
new IllegalStateException(
"Expected to be healthy after starting. The following services are not running: "
+ Multimaps.filterKeys(servicesByState, not(equalTo(RUNNING))));
for (Service service : servicesByState.get(State.FAILED)) {
exception.addSuppressed(new FailedService(service));
}
throw exception;
}
}
Expand Down Expand Up @@ -796,6 +799,11 @@ public void failed(State from, Throwable failure) {
// Log before the transition, so that if the process exits in response to server failure,
// there is a higher likelihood that the cause will be in the logs.
boolean log = !(service instanceof NoOpService);
/*
* We have already exposed startup exceptions to the user in the form of suppressed
* exceptions. We don't need to log those exceptions again.
*/
log &= from != State.STARTING;
if (log) {
logger
.get()
Expand Down Expand Up @@ -831,4 +839,14 @@ protected void doStop() {

/** This is never thrown but only used for logging. */
private static final class EmptyServiceManagerWarning extends Throwable {}

private static final class FailedService extends Throwable {
FailedService(Service service) {
super(
service.toString(),
service.failureCause(),
false /* don't enable suppression */,
false /* don't calculate a stack trace. */);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -58,8 +58,8 @@
import java.time.Duration;
import java.util.Collections;
import java.util.EnumSet;
import java.util.IdentityHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.Executor;
import java.util.concurrent.TimeUnit;
Expand Down Expand Up @@ -454,7 +454,7 @@ private static final class ServiceManagerState {
final Multiset<State> states = servicesByState.keys();

@GuardedBy("monitor")
final Map<Service, Stopwatch> startupTimers = Maps.newIdentityHashMap();
final IdentityHashMap<Service, Stopwatch> startupTimers = new IdentityHashMap<>();

/**
* These two booleans are used to mark the state as ready to start.
Expand Down

0 comments on commit 61d3f25

Please sign in to comment.