summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--services/core/java/com/android/server/utils/ManagedApplicationService.java323
-rw-r--r--services/core/java/com/android/server/vr/VrManagerService.java182
2 files changed, 400 insertions, 105 deletions
diff --git a/services/core/java/com/android/server/utils/ManagedApplicationService.java b/services/core/java/com/android/server/utils/ManagedApplicationService.java
index d965122ee3f3..c5553881cf6c 100644
--- a/services/core/java/com/android/server/utils/ManagedApplicationService.java
+++ b/services/core/java/com/android/server/utils/ManagedApplicationService.java
@@ -22,14 +22,18 @@ import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
+import android.os.Handler;
import android.os.IBinder;
import android.os.IBinder.DeathRecipient;
import android.os.IInterface;
import android.os.RemoteException;
+import android.os.SystemClock;
import android.os.UserHandle;
import android.util.Slog;
+import java.text.SimpleDateFormat;
import java.util.Objects;
+import java.util.Date;
/**
* Manages the lifecycle of an application-provided service bound from system server.
@@ -39,6 +43,40 @@ import java.util.Objects;
public class ManagedApplicationService {
private final String TAG = getClass().getSimpleName();
+ /**
+ * Attempt to reconnect service forever if an onBindingDied or onServiceDisconnected event
+ * is received.
+ */
+ public static final int RETRY_FOREVER = 1;
+
+ /**
+ * Never attempt to reconnect the service - a single onBindingDied or onServiceDisconnected
+ * event will cause this to fully unbind the service and never attempt to reconnect.
+ */
+ public static final int RETRY_NEVER = 2;
+
+ /**
+ * Attempt to reconnect the service until the maximum number of retries is reached, then stop.
+ *
+ * The first retry will occur MIN_RETRY_DURATION_MS after the disconnection, and each
+ * subsequent retry will occur after 2x the duration used for the previous retry up to the
+ * MAX_RETRY_DURATION_MS duration.
+ *
+ * In this case, retries mean a full unbindService/bindService pair to handle cases when the
+ * usual service re-connection logic in ActiveServices has very high backoff times or when the
+ * serviceconnection has fully died due to a package update or similar.
+ */
+ public static final int RETRY_BEST_EFFORT = 3;
+
+ // Maximum number of retries before giving up (for RETRY_BEST_EFFORT).
+ private static final int MAX_RETRY_COUNT = 4;
+ // Max time between retry attempts.
+ private static final long MAX_RETRY_DURATION_MS = 16000;
+ // Min time between retry attempts.
+ private static final long MIN_RETRY_DURATION_MS = 2000;
+ // Time since the last retry attempt after which to clear the retry attempt counter.
+ private static final long RETRY_RESET_TIME_MS = MAX_RETRY_DURATION_MS * 4;
+
private final Context mContext;
private final int mUserId;
private final ComponentName mComponent;
@@ -46,27 +84,75 @@ public class ManagedApplicationService {
private final String mSettingsAction;
private final BinderChecker mChecker;
private final boolean mIsImportant;
-
- private final DeathRecipient mDeathRecipient = new DeathRecipient() {
- @Override
- public void binderDied() {
- synchronized (mLock) {
- mBoundInterface = null;
- }
- }
- };
+ private final int mRetryType;
+ private final Handler mHandler;
+ private final Runnable mRetryRunnable = this::doRetry;
+ private final EventCallback mEventCb;
private final Object mLock = new Object();
// State protected by mLock
- private ServiceConnection mPendingConnection;
private ServiceConnection mConnection;
private IInterface mBoundInterface;
private PendingEvent mPendingEvent;
+ private int mRetryCount;
+ private long mLastRetryTimeMs;
+ private long mNextRetryDurationMs = MIN_RETRY_DURATION_MS;
+ private boolean mRetrying;
+
+ public static interface LogFormattable {
+ String toLogString(SimpleDateFormat dateFormat);
+ }
+
+ /**
+ * Lifecycle event of this managed service.
+ */
+ public static class LogEvent implements LogFormattable {
+ public static final int EVENT_CONNECTED = 1;
+ public static final int EVENT_DISCONNECTED = 2;
+ public static final int EVENT_BINDING_DIED = 3;
+ public static final int EVENT_STOPPED_PERMANENTLY = 4;
+
+ // Time of the events in "current time ms" timebase.
+ public final long timestamp;
+ // Name of the component for this system service.
+ public final ComponentName component;
+ // ID of the event that occurred.
+ public final int event;
+
+ public LogEvent(long timestamp, ComponentName component, int event) {
+ this.timestamp = timestamp;
+ this.component = component;
+ this.event = event;
+ }
+
+ @Override
+ public String toLogString(SimpleDateFormat dateFormat) {
+ return dateFormat.format(new Date(timestamp)) + " " + eventToString(event)
+ + " Managed Service: "
+ + ((component == null) ? "None" : component.flattenToString());
+ }
+
+ public static String eventToString(int event) {
+ switch (event) {
+ case EVENT_CONNECTED:
+ return "Connected";
+ case EVENT_DISCONNECTED:
+ return "Disconnected";
+ case EVENT_BINDING_DIED:
+ return "Binding Died For";
+ case EVENT_STOPPED_PERMANENTLY:
+ return "Permanently Stopped";
+ default:
+ return "Unknown Event Occurred";
+ }
+ }
+ }
private ManagedApplicationService(final Context context, final ComponentName component,
final int userId, int clientLabel, String settingsAction,
- BinderChecker binderChecker, boolean isImportant) {
+ BinderChecker binderChecker, boolean isImportant, int retryType, Handler handler,
+ EventCallback eventCallback) {
mContext = context;
mComponent = component;
mUserId = userId;
@@ -74,6 +160,9 @@ public class ManagedApplicationService {
mSettingsAction = settingsAction;
mChecker = binderChecker;
mIsImportant = isImportant;
+ mRetryType = retryType;
+ mHandler = handler;
+ mEventCb = eventCallback;
}
/**
@@ -88,7 +177,17 @@ public class ManagedApplicationService {
* Implement to call IInterface methods after service is connected.
*/
public interface PendingEvent {
- void runEvent(IInterface service) throws RemoteException;
+ void runEvent(IInterface service) throws RemoteException;
+ }
+
+ /**
+ * Implement to be notified about any problems with remote service.
+ */
+ public interface EventCallback {
+ /**
+ * Called when an sevice lifecycle event occurs.
+ */
+ void onServiceEvent(LogEvent event);
}
/**
@@ -104,14 +203,19 @@ public class ManagedApplicationService {
* @param binderChecker an interface used to validate the returned binder object, or null if
* this interface is unchecked.
* @param isImportant bind the user service with BIND_IMPORTANT.
+ * @param retryType reconnect behavior to have when bound service is disconnected.
+ * @param handler the Handler to use for retries and delivering EventCallbacks.
+ * @param eventCallback a callback used to deliver disconnection events, or null if you
+ * don't care.
* @return a ManagedApplicationService instance.
*/
public static ManagedApplicationService build(@NonNull final Context context,
@NonNull final ComponentName component, final int userId, int clientLabel,
@Nullable String settingsAction, @Nullable BinderChecker binderChecker,
- boolean isImportant) {
+ boolean isImportant, int retryType, @NonNull Handler handler,
+ @Nullable EventCallback eventCallback) {
return new ManagedApplicationService(context, component, userId, clientLabel,
- settingsAction, binderChecker, isImportant);
+ settingsAction, binderChecker, isImportant, retryType, handler, eventCallback);
}
@@ -145,13 +249,12 @@ public class ManagedApplicationService {
return true;
}
-
- /**
- * Send an event to run as soon as the binder interface is available.
- *
- * @param event a {@link PendingEvent} to send.
- */
- public void sendEvent(@NonNull PendingEvent event) {
+ /**
+ * Send an event to run as soon as the binder interface is available.
+ *
+ * @param event a {@link PendingEvent} to send.
+ */
+ public void sendEvent(@NonNull PendingEvent event) {
IInterface iface;
synchronized (mLock) {
iface = mBoundInterface;
@@ -174,15 +277,13 @@ public class ManagedApplicationService {
*/
public void disconnect() {
synchronized (mLock) {
- // Wipe out pending connections
- mPendingConnection = null;
-
// Unbind existing connection, if it exists
- if (mConnection != null) {
- mContext.unbindService(mConnection);
- mConnection = null;
+ if (mConnection == null) {
+ return;
}
+ mContext.unbindService(mConnection);
+ mConnection = null;
mBoundInterface = null;
}
}
@@ -192,7 +293,7 @@ public class ManagedApplicationService {
*/
public void connect() {
synchronized (mLock) {
- if (mConnection != null || mPendingConnection != null) {
+ if (mConnection != null) {
// We're already connected or are trying to connect
return;
}
@@ -206,40 +307,56 @@ public class ManagedApplicationService {
PendingIntent.getActivity(mContext, 0, new Intent(mSettingsAction), 0));
}
- final ServiceConnection serviceConnection = new ServiceConnection() {
+ mConnection = new ServiceConnection() {
+ @Override
+ public void onBindingDied(ComponentName componentName) {
+ final long timestamp = System.currentTimeMillis();
+ Slog.w(TAG, "Service binding died: " + componentName);
+ synchronized (mLock) {
+ if (mConnection != this) {
+ return;
+ }
+ mHandler.post(() -> {
+ mEventCb.onServiceEvent(new LogEvent(timestamp, mComponent,
+ LogEvent.EVENT_BINDING_DIED));
+ });
+
+ mBoundInterface = null;
+ startRetriesLocked();
+ }
+ }
+
@Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
+ final long timestamp = System.currentTimeMillis();
+ Slog.i(TAG, "Service connected: " + componentName);
IInterface iface = null;
PendingEvent pendingEvent = null;
synchronized (mLock) {
- if (mPendingConnection == this) {
- // No longer pending, remove from pending connection
- mPendingConnection = null;
- mConnection = this;
- } else {
- // Service connection wasn't pending, must have been disconnected
- mContext.unbindService(this);
+ if (mConnection != this) {
+ // Must've been unbound.
return;
}
+ mHandler.post(() -> {
+ mEventCb.onServiceEvent(new LogEvent(timestamp, mComponent,
+ LogEvent.EVENT_CONNECTED));
+ });
- try {
- iBinder.linkToDeath(mDeathRecipient, 0);
- mBoundInterface = null;
- if (mChecker != null) {
- mBoundInterface = mChecker.asInterface(iBinder);
- if (!mChecker.checkType(mBoundInterface)) {
- // Received an invalid binder, disconnect
- mContext.unbindService(this);
- mBoundInterface = null;
- }
- iface = mBoundInterface;
- pendingEvent = mPendingEvent;
- mPendingEvent = null;
+ stopRetriesLocked();
+
+ mBoundInterface = null;
+ if (mChecker != null) {
+ mBoundInterface = mChecker.asInterface(iBinder);
+ if (!mChecker.checkType(mBoundInterface)) {
+ // Received an invalid binder, disconnect.
+ mBoundInterface = null;
+ Slog.w(TAG, "Invalid binder from " + componentName);
+ startRetriesLocked();
+ return;
}
- } catch (RemoteException e) {
- // DOA
- Slog.w(TAG, "Unable to bind service: " + componentName, e);
- mBoundInterface = null;
+ iface = mBoundInterface;
+ pendingEvent = mPendingEvent;
+ mPendingEvent = null;
}
}
if (iface != null && pendingEvent != null) {
@@ -247,31 +364,44 @@ public class ManagedApplicationService {
pendingEvent.runEvent(iface);
} catch (RuntimeException | RemoteException ex) {
Slog.e(TAG, "Received exception from user service: ", ex);
+ startRetriesLocked();
}
}
}
@Override
public void onServiceDisconnected(ComponentName componentName) {
+ final long timestamp = System.currentTimeMillis();
Slog.w(TAG, "Service disconnected: " + componentName);
- mConnection = null;
- mBoundInterface = null;
+ synchronized (mLock) {
+ if (mConnection != this) {
+ return;
+ }
+
+ mHandler.post(() -> {
+ mEventCb.onServiceEvent(new LogEvent(timestamp, mComponent,
+ LogEvent.EVENT_DISCONNECTED));
+ });
+
+ mBoundInterface = null;
+ startRetriesLocked();
+ }
}
};
- mPendingConnection = serviceConnection;
-
int flags = Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE;
if (mIsImportant) {
flags |= Context.BIND_IMPORTANT;
}
try {
- if (!mContext.bindServiceAsUser(intent, serviceConnection, flags,
+ if (!mContext.bindServiceAsUser(intent, mConnection, flags,
new UserHandle(mUserId))) {
Slog.w(TAG, "Unable to bind service: " + intent);
+ startRetriesLocked();
}
} catch (SecurityException e) {
Slog.w(TAG, "Unable to bind service: " + intent, e);
+ startRetriesLocked();
}
}
}
@@ -279,4 +409,81 @@ public class ManagedApplicationService {
private boolean matches(final ComponentName component, final int userId) {
return Objects.equals(mComponent, component) && mUserId == userId;
}
+
+ private void startRetriesLocked() {
+ if (checkAndDeliverServiceDiedCbLocked()) {
+ // If we delivered the service callback, disconnect and stop retrying.
+ disconnect();
+ return;
+ }
+
+ if (mRetrying) {
+ // Retry already queued, don't queue a new one.
+ return;
+ }
+ mRetrying = true;
+ queueRetryLocked();
+ }
+
+ private void stopRetriesLocked() {
+ mRetrying = false;
+ mHandler.removeCallbacks(mRetryRunnable);
+ }
+
+ private void queueRetryLocked() {
+ long now = SystemClock.uptimeMillis();
+ if ((now - mLastRetryTimeMs) > RETRY_RESET_TIME_MS) {
+ // It's been longer than the reset time since we last had to retry. Re-initialize.
+ mNextRetryDurationMs = MIN_RETRY_DURATION_MS;
+ mRetryCount = 0;
+ }
+ mLastRetryTimeMs = now;
+ mHandler.postDelayed(mRetryRunnable, mNextRetryDurationMs);
+ mNextRetryDurationMs = Math.min(2 * mNextRetryDurationMs, MAX_RETRY_DURATION_MS);
+ mRetryCount++;
+ }
+
+ private boolean checkAndDeliverServiceDiedCbLocked() {
+
+ if (mRetryType == RETRY_NEVER || (mRetryType == RETRY_BEST_EFFORT
+ && mRetryCount >= MAX_RETRY_COUNT)) {
+ // If we never retry, or we've exhausted our retries, post the onServiceDied callback.
+ Slog.e(TAG, "Service " + mComponent + " has died too much, not retrying.");
+ if (mEventCb != null) {
+ final long timestamp = System.currentTimeMillis();
+ mHandler.post(() -> {
+ mEventCb.onServiceEvent(new LogEvent(timestamp, mComponent,
+ LogEvent.EVENT_STOPPED_PERMANENTLY));
+ });
+ }
+ return true;
+ }
+ return false;
+ }
+
+ private void doRetry() {
+ synchronized (mLock) {
+ if (mConnection == null) {
+ // We disconnected for good. Don't attempt to retry.
+ return;
+ }
+ if (!mRetrying) {
+ // We successfully connected. Don't attempt to retry.
+ return;
+ }
+ Slog.i(TAG, "Attempting to reconnect " + mComponent + "...");
+ // While frameworks may restart the remote Service if we stay bound, we have little
+ // control of the backoff timing for reconnecting the service. In the event of a
+ // process crash, the backoff time can be very large (1-30 min), which is not
+ // acceptable for the types of services this is used for. Instead force an unbind/bind
+ // sequence to cause a more immediate retry.
+ disconnect();
+ if (checkAndDeliverServiceDiedCbLocked()) {
+ // No more retries.
+ return;
+ }
+ queueRetryLocked();
+ connect();
+ }
+ }
}
diff --git a/services/core/java/com/android/server/vr/VrManagerService.java b/services/core/java/com/android/server/vr/VrManagerService.java
index 5a8de82866f2..f06f76dc9edb 100644
--- a/services/core/java/com/android/server/vr/VrManagerService.java
+++ b/services/core/java/com/android/server/vr/VrManagerService.java
@@ -66,6 +66,8 @@ import com.android.server.LocalServices;
import com.android.server.SystemConfig;
import com.android.server.SystemService;
import com.android.server.utils.ManagedApplicationService.PendingEvent;
+import com.android.server.utils.ManagedApplicationService.LogEvent;
+import com.android.server.utils.ManagedApplicationService.LogFormattable;
import com.android.server.vr.EnabledComponentsObserver.EnabledComponentChangeListener;
import com.android.server.utils.ManagedApplicationService;
import com.android.server.utils.ManagedApplicationService.BinderChecker;
@@ -108,7 +110,7 @@ public class VrManagerService extends SystemService implements EnabledComponentC
static final boolean DBG = false;
private static final int PENDING_STATE_DELAY_MS = 300;
- private static final int EVENT_LOG_SIZE = 32;
+ private static final int EVENT_LOG_SIZE = 64;
private static final int INVALID_APPOPS_MODE = -1;
/** Null set of sleep sleep flags. */
private static final int FLAG_NONE = 0;
@@ -148,7 +150,8 @@ public class VrManagerService extends SystemService implements EnabledComponentC
private int mPreviousCoarseLocationMode = INVALID_APPOPS_MODE;
private int mPreviousManageOverlayMode = INVALID_APPOPS_MODE;
private VrState mPendingState;
- private final ArrayDeque<VrState> mLoggingDeque = new ArrayDeque<>(EVENT_LOG_SIZE);
+ private boolean mLogLimitHit;
+ private final ArrayDeque<LogFormattable> mLoggingDeque = new ArrayDeque<>(EVENT_LOG_SIZE);
private final NotificationAccessManager mNotifAccessManager = new NotificationAccessManager();
private INotificationManager mNotificationManager;
/** Tracks the state of the screen and keyguard UI.*/
@@ -161,6 +164,30 @@ public class VrManagerService extends SystemService implements EnabledComponentC
private Vr2dDisplay mVr2dDisplay;
private boolean mBootsToVr;
+ // Handles events from the managed services (e.g. VrListenerService and any bound VR compositor
+ // service).
+ private final ManagedApplicationService.EventCallback mEventCallback
+ = new ManagedApplicationService.EventCallback() {
+ @Override
+ public void onServiceEvent(LogEvent event) {
+ logEvent(event);
+
+ ComponentName component = null;
+ synchronized (mLock) {
+ component = ((mCurrentVrService == null) ? null : mCurrentVrService.getComponent());
+ }
+
+ // If not on an AIO device and we permanently stopped trying to connect to the
+ // VrListenerService (or don't have one bound), leave persistent VR mode and VR mode.
+ if (!mBootsToVr && event.event == LogEvent.EVENT_STOPPED_PERMANENTLY &&
+ (component == null || component.equals(event.component))) {
+ Slog.e(TAG, "VrListenerSevice has died permanently, leaving system VR mode.");
+ // We're not a native VR device. Leave VR + persistent mode.
+ setPersistentVrModeEnabled(false);
+ }
+ }
+ };
+
private static final int MSG_VR_STATE_CHANGE = 0;
private static final int MSG_PENDING_VR_STATE_CHANGE = 1;
private static final int MSG_PERSISTENT_VR_MODE_STATE_CHANGE = 2;
@@ -277,7 +304,24 @@ public class VrManagerService extends SystemService implements EnabledComponentC
}
};
- private static class VrState {
+ // Event used to log when settings are changed for dumpsys logs.
+ private static class SettingEvent implements LogFormattable {
+ public final long timestamp;
+ public final String what;
+
+ SettingEvent(String what) {
+ this.timestamp = System.currentTimeMillis();
+ this.what = what;
+ }
+
+ @Override
+ public String toLogString(SimpleDateFormat dateFormat) {
+ return dateFormat.format(new Date(timestamp)) + " " + what;
+ }
+ }
+
+ // Event used to track changes of the primary on-screen VR activity.
+ private static class VrState implements LogFormattable {
final boolean enabled;
final boolean running2dInVr;
final int userId;
@@ -287,7 +331,6 @@ public class VrManagerService extends SystemService implements EnabledComponentC
final long timestamp;
final boolean defaultPermissionsGranted;
-
VrState(boolean enabled, boolean running2dInVr, ComponentName targetPackageName, int userId,
int processId, ComponentName callingPackage) {
this.enabled = enabled;
@@ -311,6 +354,39 @@ public class VrManagerService extends SystemService implements EnabledComponentC
this.defaultPermissionsGranted = defaultPermissionsGranted;
this.timestamp = System.currentTimeMillis();
}
+
+ @Override
+ public String toLogString(SimpleDateFormat dateFormat) {
+ String tab = " ";
+ String newLine = "\n";
+ StringBuilder sb = new StringBuilder(dateFormat.format(new Date(timestamp)));
+ sb.append(tab);
+ sb.append("State changed to:");
+ sb.append(tab);
+ sb.append((enabled) ? "ENABLED" : "DISABLED");
+ sb.append(newLine);
+ if (enabled) {
+ sb.append(tab);
+ sb.append("User=");
+ sb.append(userId);
+ sb.append(newLine);
+ sb.append(tab);
+ sb.append("Current VR Activity=");
+ sb.append((callingPackage == null) ? "None" : callingPackage.flattenToString());
+ sb.append(newLine);
+ sb.append(tab);
+ sb.append("Bound VrListenerService=");
+ sb.append((targetPackageName == null) ? "None"
+ : targetPackageName.flattenToString());
+ sb.append(newLine);
+ if (defaultPermissionsGranted) {
+ sb.append(tab);
+ sb.append("Default permissions granted to the bound VrListenerService.");
+ sb.append(newLine);
+ }
+ }
+ return sb.toString();
+ }
}
private static final BinderChecker sBinderChecker = new BinderChecker() {
@@ -505,9 +581,12 @@ public class VrManagerService extends SystemService implements EnabledComponentC
pw.println("VR mode is currently: " + ((mVrModeAllowed) ? "allowed" : "disallowed"));
pw.println("Persistent VR mode is currently: " +
((mPersistentVrModeEnabled) ? "enabled" : "disabled"));
+ pw.println("Currently bound VR listener service: "
+ + ((mCurrentVrService == null)
+ ? "None" : mCurrentVrCompositorService.getComponent().flattenToString()));
pw.println("Currently bound VR compositor service: "
+ ((mCurrentVrCompositorService == null)
- ? "None" : mCurrentVrCompositorService.getComponent()));
+ ? "None" : mCurrentVrCompositorService.getComponent().flattenToString()));
pw.println("Previous state transitions:\n");
String tab = " ";
dumpStateTransitions(pw);
@@ -998,7 +1077,7 @@ public class VrManagerService extends SystemService implements EnabledComponentC
private void createAndConnectService(@NonNull ComponentName component, int userId) {
- mCurrentVrService = VrManagerService.create(mContext, component, userId);
+ mCurrentVrService = createVrListenerService(component, userId);
mCurrentVrService.connect();
Slog.i(TAG, "Connecting " + component + " for user " + userId);
}
@@ -1033,13 +1112,27 @@ public class VrManagerService extends SystemService implements EnabledComponentC
}
/**
- * Helper function for making ManagedApplicationService instances.
+ * Helper function for making ManagedApplicationService for VrListenerService instances.
*/
- private static ManagedApplicationService create(@NonNull Context context,
- @NonNull ComponentName component, int userId) {
- return ManagedApplicationService.build(context, component, userId,
+ private ManagedApplicationService createVrListenerService(@NonNull ComponentName component,
+ int userId) {
+ int retryType = (mBootsToVr) ? ManagedApplicationService.RETRY_FOREVER
+ : ManagedApplicationService.RETRY_NEVER;
+ return ManagedApplicationService.build(mContext, component, userId,
R.string.vr_listener_binding_label, Settings.ACTION_VR_LISTENER_SETTINGS,
- sBinderChecker, /*isImportant*/true);
+ sBinderChecker, /*isImportant*/true, retryType, mHandler, mEventCallback);
+ }
+
+ /**
+ * Helper function for making ManagedApplicationService for VR Compositor instances.
+ */
+ private ManagedApplicationService createVrCompositorService(@NonNull ComponentName component,
+ int userId) {
+ int retryType = (mBootsToVr) ? ManagedApplicationService.RETRY_FOREVER
+ : ManagedApplicationService.RETRY_BEST_EFFORT;
+ return ManagedApplicationService.build(mContext, component, userId, /*clientLabel*/0,
+ /*settingsAction*/null, /*binderChecker*/null, /*isImportant*/true, retryType,
+ mHandler, /*disconnectCallback*/mEventCallback);
}
/**
@@ -1070,44 +1163,35 @@ public class VrManagerService extends SystemService implements EnabledComponentC
private void logStateLocked() {
ComponentName currentBoundService = (mCurrentVrService == null) ? null :
- mCurrentVrService.getComponent();
- VrState current = new VrState(mVrModeEnabled, mRunning2dInVr, currentBoundService,
- mCurrentVrModeUser, mVrAppProcessId, mCurrentVrModeComponent, mWasDefaultGranted);
- if (mLoggingDeque.size() == EVENT_LOG_SIZE) {
- mLoggingDeque.removeFirst();
+ mCurrentVrService.getComponent();
+ logEvent(new VrState(mVrModeEnabled, mRunning2dInVr, currentBoundService,
+ mCurrentVrModeUser, mVrAppProcessId, mCurrentVrModeComponent, mWasDefaultGranted));
+ }
+
+ private void logEvent(LogFormattable event) {
+ synchronized (mLoggingDeque) {
+ if (mLoggingDeque.size() == EVENT_LOG_SIZE) {
+ mLoggingDeque.removeFirst();
+ mLogLimitHit = true;
+ }
+ mLoggingDeque.add(event);
}
- mLoggingDeque.add(current);
}
private void dumpStateTransitions(PrintWriter pw) {
SimpleDateFormat d = new SimpleDateFormat("MM-dd HH:mm:ss.SSS");
- String tab = " ";
- if (mLoggingDeque.size() == 0) {
- pw.print(tab);
- pw.println("None");
- }
- for (VrState state : mLoggingDeque) {
- pw.print(d.format(new Date(state.timestamp)));
- pw.print(tab);
- pw.print("State changed to:");
- pw.print(tab);
- pw.println((state.enabled) ? "ENABLED" : "DISABLED");
- if (state.enabled) {
- pw.print(tab);
- pw.print("User=");
- pw.println(state.userId);
- pw.print(tab);
- pw.print("Current VR Activity=");
- pw.println((state.callingPackage == null) ?
- "None" : state.callingPackage.flattenToString());
- pw.print(tab);
- pw.print("Bound VrListenerService=");
- pw.println((state.targetPackageName == null) ?
- "None" : state.targetPackageName.flattenToString());
- if (state.defaultPermissionsGranted) {
- pw.print(tab);
- pw.println("Default permissions granted to the bound VrListenerService.");
- }
+ synchronized (mLoggingDeque) {
+ if (mLoggingDeque.size() == 0) {
+ pw.print(" ");
+ pw.println("None");
+ }
+
+ if (mLogLimitHit) {
+ pw.println("..."); // Indicates log overflow
+ }
+
+ for (LogFormattable event : mLoggingDeque) {
+ pw.println(event.toLogString(d));
}
}
}
@@ -1202,6 +1286,8 @@ public class VrManagerService extends SystemService implements EnabledComponentC
private void updateCompositorServiceLocked(int userId, ComponentName componentName) {
if (mCurrentVrCompositorService != null
&& mCurrentVrCompositorService.disconnectIfNotMatching(componentName, userId)) {
+ Slog.i(TAG, "Disconnecting compositor service: "
+ + mCurrentVrCompositorService.getComponent());
// Check if existing service matches the requested one, if not (or if the requested
// component is null) disconnect it.
mCurrentVrCompositorService = null;
@@ -1210,9 +1296,8 @@ public class VrManagerService extends SystemService implements EnabledComponentC
if (componentName != null && mCurrentVrCompositorService == null) {
// We don't have an existing service matching the requested component, so attempt to
// connect one.
- mCurrentVrCompositorService = ManagedApplicationService.build(mContext,
- componentName, userId, /*clientLabel*/0, /*settingsAction*/null,
- /*binderChecker*/null, /*isImportant*/true);
+ Slog.i(TAG, "Connecting compositor service: " + componentName);
+ mCurrentVrCompositorService = createVrCompositorService(componentName, userId);
mCurrentVrCompositorService.connect();
}
}
@@ -1221,6 +1306,9 @@ public class VrManagerService extends SystemService implements EnabledComponentC
if (mPersistentVrModeEnabled == enabled) {
return;
}
+ String eventName = "Persistent VR mode " + ((enabled) ? "enabled" : "disabled");
+ Slog.i(TAG, eventName);
+ logEvent(new SettingEvent(eventName));
mPersistentVrModeEnabled = enabled;
mHandler.sendMessage(mHandler.obtainMessage(MSG_PERSISTENT_VR_MODE_STATE_CHANGE,