ipc/android: Run spotlessApply to format Java and Kotlin code

This commit is contained in:
Ryan Pavlik 2023-04-17 10:56:16 -05:00
parent fc3af6f711
commit 9840730169
5 changed files with 163 additions and 188 deletions

View file

@ -7,7 +7,6 @@
* @ingroup ipc_android
*/
package org.freedesktop.monado.ipc;
import android.app.Activity;
@ -37,50 +36,40 @@ import java.util.concurrent.Executors;
/**
* Provides the client-side code to initiate connection to Monado IPC service.
* <p>
* This class will get loaded into the OpenXR client application by our native code.
*
* <p>This class will get loaded into the OpenXR client application by our native code.
*/
@Keep
public class Client implements ServiceConnection {
private static final String TAG = "monado-ipc-client";
/**
* Used to block until binder is ready.
*/
/** Used to block until binder is ready. */
private final Object binderSync = new Object();
/**
* Keep track of the ipc_client_android instance over on the native side.
*/
/** Keep track of the ipc_client_android instance over on the native side. */
private final NativeCounterpart nativeCounterpart;
/**
* Pointer to local IPC proxy: calling methods on it automatically transports arguments across binder IPC.
* <p>
* May be null!
* Pointer to local IPC proxy: calling methods on it automatically transports arguments across
* binder IPC.
*
* <p>May be null!
*/
@Keep
public IMonado monado = null;
@Keep public IMonado monado = null;
/**
* Indicates that we tried to connect but failed.
* <p>
* Used to distinguish a "not yet fully connected" null monado member from a "tried and failed"
* null monado member.
*
* <p>Used to distinguish a "not yet fully connected" null monado member from a "tried and
* failed" null monado member.
*/
@Keep
public boolean failed = false;
@Keep public boolean failed = false;
/**
* "Our" side of the socket pair - the other side is sent to the server automatically on connection.
* "Our" side of the socket pair - the other side is sent to the server automatically on
* connection.
*/
private ParcelFileDescriptor fd = null;
/**
* Context provided by app.
*/
/** Context provided by app. */
private Context context = null;
/**
* Context of the runtime package
*/
/** Context of the runtime package */
private Context runtimePackageContext = null;
/**
* Control system ui visibility
*/
/** Control system ui visibility */
private SystemUiController systemUiController = null;
/**
@ -110,9 +99,7 @@ public class Client implements ServiceConnection {
}
}
/**
* Let the native code notify us that it is no longer using this class.
*/
/** Let the native code notify us that it is no longer using this class. */
@Keep
public void markAsDiscardedByNative() {
nativeCounterpart.markAsDiscardedByNative(TAG);
@ -121,22 +108,21 @@ public class Client implements ServiceConnection {
/**
* Bind to the Monado IPC service, and block until it is fully connected.
* <p>
* The IPC client code on Android should load this class (from the right package), instantiate
* this class (retaining a reference to it!), and call this method.
* <p>
* This method must not be called from the main (UI) thread.
*
* @param context_ Context to use to make the connection. (We get the application context
* from it.)
* <p>The IPC client code on Android should load this class (from the right package),
* instantiate this class (retaining a reference to it!), and call this method.
*
* <p>This method must not be called from the main (UI) thread.
*
* @param context_ Context to use to make the connection. (We get the application context from
* it.)
* @param packageName The package name containing the Monado runtime. The caller is guaranteed
* to know this because it had to load this class from that package.
* There's a define in xrt_config_android.h to use for this.
* to know this because it had to load this class from that package. There's a define in
* xrt_config_android.h to use for this.
* @return the fd number - do not close! (dup if you want to be able to close it) Returns -1 if
* something went wrong.
* <p>
* Various builds, variants, etc. will have different package names, but we must specify the
* package name explicitly to avoid violating security restrictions.
* something went wrong.
* <p>Various builds, variants, etc. will have different package names, but we must specify
* the package name explicitly to avoid violating security restrictions.
*/
@Keep
public int blockingConnect(Context context_, String packageName) {
@ -167,42 +153,49 @@ public class Client implements ServiceConnection {
// TODO: just initiate MonadoView attachment and add callback to native code to
// notify about Surface status and pass it to OpenXR application as a Session lifecycle
// (ready ... synchronized ... visible ... focused)
new Thread(()-> {
boolean surfaceCreated = false;
Activity activity = null;
if (context_ instanceof Activity) {
activity = (Activity) context_;
}
new Thread(
() -> {
boolean surfaceCreated = false;
Activity activity = null;
if (context_ instanceof Activity) {
activity = (Activity) context_;
}
try {
// Determine whether runtime or client should create surface
if (monado.canDrawOverOtherApps()) {
WindowManager wm = (WindowManager) context_.getSystemService(Context.WINDOW_SERVICE);
surfaceCreated = monado.createSurface(wm.getDefaultDisplay().getDisplayId(), false);
} else {
if (activity != null) {
Surface surface = attachViewAndGetSurface(activity);
surfaceCreated = (surface != null);
if (surfaceCreated) {
monado.passAppSurface(surface);
}
}
}
} catch (RemoteException e) {
e.printStackTrace();
}
try {
// Determine whether runtime or client should create surface
if (monado.canDrawOverOtherApps()) {
WindowManager wm =
(WindowManager)
context_.getSystemService(
Context.WINDOW_SERVICE);
surfaceCreated =
monado.createSurface(
wm.getDefaultDisplay().getDisplayId(), false);
} else {
if (activity != null) {
Surface surface = attachViewAndGetSurface(activity);
surfaceCreated = (surface != null);
if (surfaceCreated) {
monado.passAppSurface(surface);
}
}
}
} catch (RemoteException e) {
e.printStackTrace();
}
if (!surfaceCreated) {
Log.e(TAG, "Failed to create surface");
handleFailure();
return;
}
if (!surfaceCreated) {
Log.e(TAG, "Failed to create surface");
handleFailure();
return;
}
if (activity != null) {
systemUiController = new SystemUiController(activity);
systemUiController.hide();
}
}).start();
if (activity != null) {
systemUiController = new SystemUiController(activity);
systemUiController.hide();
}
})
.start();
// Create socket pair
ParcelFileDescriptor theirs;
@ -233,15 +226,13 @@ public class Client implements ServiceConnection {
* Bind to the Monado IPC service - this asynchronously starts connecting (and launching the
* service if it's not already running)
*
* @param context_ Context to use to make the connection. (We get the application context
* from it.)
* @param context_ Context to use to make the connection. (We get the application context from
* it.)
* @param packageName The package name containing the Monado runtime. The caller is guaranteed
* to know this because it had to load this class from that package.
* There's a define in xrt_config_android.h to use for this.
* <p>
* Various builds, variants, etc. will have different package names, but we
* must specify the package name explicitly to avoid violating security
* restrictions.
* to know this because it had to load this class from that package. There's a define in
* xrt_config_android.h to use for this.
* <p>Various builds, variants, etc. will have different package names, but we must specify
* the package name explicitly to avoid violating security restrictions.
*/
public boolean bind(Context context_, String packageName) {
Log.i(TAG, "bind");
@ -251,20 +242,20 @@ public class Client implements ServiceConnection {
context = context_;
}
try {
runtimePackageContext = context.createPackageContext(packageName,
Context.CONTEXT_IGNORE_SECURITY | Context.CONTEXT_INCLUDE_CODE);
runtimePackageContext =
context.createPackageContext(
packageName,
Context.CONTEXT_IGNORE_SECURITY | Context.CONTEXT_INCLUDE_CODE);
} catch (PackageManager.NameNotFoundException e) {
e.printStackTrace();
Log.e(TAG, "bind: Could not find package " + packageName);
return false;
}
Intent intent = new Intent(BuildConfig.SERVICE_ACTION)
.setPackage(packageName);
Intent intent = new Intent(BuildConfig.SERVICE_ACTION).setPackage(packageName);
if (!bindService(context, intent)) {
Log.e(TAG,
"bindService: Service " + intent + " could not be found to bind!");
Log.e(TAG, "bindService: Service " + intent + " could not be found to bind!");
return false;
}
@ -276,8 +267,12 @@ public class Client implements ServiceConnection {
boolean result;
int flags = Context.BIND_AUTO_CREATE | Context.BIND_IMPORTANT | Context.BIND_ABOVE_CLIENT;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
result = context.bindService(intent, flags | Context.BIND_INCLUDE_CAPABILITIES,
Executors.newSingleThreadExecutor(), this);
result =
context.bindService(
intent,
flags | Context.BIND_INCLUDE_CAPABILITIES,
Executors.newSingleThreadExecutor(),
this);
} else {
result = context.bindService(intent, this, flags);
}
@ -285,16 +280,13 @@ public class Client implements ServiceConnection {
return result;
}
/**
* Some on-failure cleanup.
*/
/** Some on-failure cleanup. */
private void handleFailure() {
failed = true;
shutdown();
}
@Nullable
private Surface attachViewAndGetSurface(Activity activity) {
@Nullable private Surface attachViewAndGetSurface(Activity activity) {
MonadoView monadoView = MonadoView.attachToActivity(activity);
SurfaceHolder holder = monadoView.waitGetSurfaceHolder(2000);
Surface surface = null;
@ -308,7 +300,7 @@ public class Client implements ServiceConnection {
/**
* Handle the asynchronous connection of the binder IPC.
*
* @param name should match the preceding intent, but not used.
* @param name should match the preceding intent, but not used.
* @param service the associated service, which we cast in this function.
*/
@Override
@ -330,7 +322,7 @@ public class Client implements ServiceConnection {
public void onServiceDisconnected(ComponentName name) {
Log.i(TAG, "onServiceDisconnected");
shutdown();
//! @todo tell C/C++ that the world is crumbling, then close the fd here.
// ! @todo tell C/C++ that the world is crumbling, then close the fd here.
}
/*

View file

@ -7,7 +7,6 @@
* @ingroup ipc_android
*/
package org.freedesktop.monado.ipc;
import android.os.ParcelFileDescriptor;
@ -23,12 +22,12 @@ import java.io.IOException;
/**
* Java implementation of the IMonado IPC interface.
* <p>
* (This is the server-side code.)
* <p>
* All this does is delegate calls to native JNI implementations.
* The warning suppression is because Android Studio tends to have a hard time finding
* the (very real) implementations of these in service-lib.
*
* <p>(This is the server-side code.)
*
* <p>All this does is delegate calls to native JNI implementations. The warning suppression is
* because Android Studio tends to have a hard time finding the (very real) implementations of these
* in service-lib.
*/
@Keep
public class MonadoImpl extends IMonado.Stub {
@ -45,21 +44,21 @@ public class MonadoImpl extends IMonado.Stub {
public MonadoImpl(@NonNull SurfaceManager surfaceManager) {
this.surfaceManager = surfaceManager;
this.surfaceManager.setCallback(new SurfaceHolder.Callback() {
@Override
public void surfaceCreated(@NonNull SurfaceHolder holder) {
Log.i(TAG, "surfaceCreated");
passAppSurface(holder.getSurface());
}
this.surfaceManager.setCallback(
new SurfaceHolder.Callback() {
@Override
public void surfaceCreated(@NonNull SurfaceHolder holder) {
Log.i(TAG, "surfaceCreated");
passAppSurface(holder.getSurface());
}
@Override
public void surfaceChanged(@NonNull SurfaceHolder holder, int format, int width, int height) {
}
@Override
public void surfaceChanged(
@NonNull SurfaceHolder holder, int format, int width, int height) {}
@Override
public void surfaceDestroyed(@NonNull SurfaceHolder holder) {
}
});
@Override
public void surfaceDestroyed(@NonNull SurfaceHolder holder) {}
});
}
@Override
@ -111,18 +110,16 @@ public class MonadoImpl extends IMonado.Stub {
nativeShutdownServer();
}
/**
* Native method that starts server.
*/
/** Native method that starts server. */
@SuppressWarnings("JavaJniMissingFunction")
private native void nativeStartServer();
/**
* Native handling of receiving a surface: should convert it to an ANativeWindow then do stuff
* with it.
* <p>
* Ignore warnings that this function is missing: it is not, it is just in a different module.
* See `src/xrt/targets/service-lib/service_target.cpp` for the implementation.
*
* <p>Ignore warnings that this function is missing: it is not, it is just in a different
* module. See `src/xrt/targets/service-lib/service_target.cpp` for the implementation.
*
* @param surface The surface to pass to native code
* @todo figure out a good way to have a client ID
@ -133,13 +130,13 @@ public class MonadoImpl extends IMonado.Stub {
/**
* Native handling of receiving an FD for a new client: the FD should be used to start up the
* rest of the native IPC code on that socket.
* <p>
* This is essentially the entry point for the monado service on Android: if it's already
*
* <p>This is essentially the entry point for the monado service on Android: if it's already
* running, this will be called in it. If it's not already running, a process will be created,
* and this will be the first native code executed in that process.
* <p>
* Ignore warnings that this function is missing: it is not, it is just in a different module.
* See `src/xrt/targets/service-lib/service_target.cpp` for the implementation.
*
* <p>Ignore warnings that this function is missing: it is not, it is just in a different
* module. See `src/xrt/targets/service-lib/service_target.cpp` for the implementation.
*
* @param fd The incoming file descriptor: ownership is transferred to native code here.
* @return 0 on success, anything else means the fd wasn't sent and ownership not transferred.

View file

@ -16,8 +16,8 @@ import android.os.Build
import android.os.IBinder
import android.util.Log
import dagger.hilt.android.AndroidEntryPoint
import org.freedesktop.monado.auxiliary.IServiceNotification
import javax.inject.Inject
import org.freedesktop.monado.auxiliary.IServiceNotification
/**
* Implementation of a Service that provides the Monado AIDL interface.
@ -30,8 +30,7 @@ class MonadoService : Service(), Watchdog.ShutdownListener {
private lateinit var watchdog: Watchdog
@Inject
lateinit var serviceNotification: IServiceNotification
@Inject lateinit var serviceNotification: IServiceNotification
private lateinit var surfaceManager: SurfaceManager
@ -40,12 +39,14 @@ class MonadoService : Service(), Watchdog.ShutdownListener {
surfaceManager = SurfaceManager(this)
binder = MonadoImpl(surfaceManager)
watchdog = Watchdog(
// If the surface comes from client, just stop the service when client disconnected
// because the surface belongs to the client.
if (surfaceManager.canDrawOverlays()) BuildConfig.WATCHDOG_TIMEOUT_MILLISECONDS else 0,
this
)
watchdog =
Watchdog(
// If the surface comes from client, just stop the service when client disconnected
// because the surface belongs to the client.
if (surfaceManager.canDrawOverlays()) BuildConfig.WATCHDOG_TIMEOUT_MILLISECONDS
else 0,
this
)
watchdog.startMonitor()
// start the service so it could be foregrounded
@ -58,7 +59,7 @@ class MonadoService : Service(), Watchdog.ShutdownListener {
super.onDestroy()
Log.d(TAG, "onDestroy")
binder.shutdown();
binder.shutdown()
watchdog.stopMonitor()
surfaceManager.destroySurface()
}
@ -76,7 +77,7 @@ class MonadoService : Service(), Watchdog.ShutdownListener {
}
override fun onBind(intent: Intent): IBinder? {
Log.d(TAG, "onBind");
Log.d(TAG, "onBind")
watchdog.onClientConnected()
return binder
}
@ -87,12 +88,13 @@ class MonadoService : Service(), Watchdog.ShutdownListener {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
flags = PendingIntent.FLAG_IMMUTABLE
}
val pendingShutdownIntent = PendingIntent.getForegroundService(
this,
0,
Intent(BuildConfig.SHUTDOWN_ACTION).setPackage(packageName),
flags
)
val pendingShutdownIntent =
PendingIntent.getForegroundService(
this,
0,
Intent(BuildConfig.SHUTDOWN_ACTION).setPackage(packageName),
flags
)
val notification = serviceNotification.buildNotification(this, pendingShutdownIntent)
@ -103,21 +105,18 @@ class MonadoService : Service(), Watchdog.ShutdownListener {
ServiceInfo.FOREGROUND_SERVICE_TYPE_MANIFEST
)
} else {
startForeground(
serviceNotification.getNotificationId(),
notification
)
startForeground(serviceNotification.getNotificationId(), notification)
}
}
override fun onUnbind(intent: Intent?): Boolean {
Log.d(TAG, "onUnbind");
Log.d(TAG, "onUnbind")
watchdog.onClientDisconnected()
return true;
return true
}
override fun onRebind(intent: Intent?) {
Log.d(TAG, "onRebind");
Log.d(TAG, "onRebind")
watchdog.onClientConnected()
}

View file

@ -24,9 +24,7 @@ import java.util.concurrent.TimeUnit
import java.util.concurrent.locks.Condition
import java.util.concurrent.locks.ReentrantLock
/**
* Class that creates/manages surface on display.
*/
/** Class that creates/manages surface on display. */
class SurfaceManager(context: Context) : SurfaceHolder.Callback {
private val appContext: Context = context.applicationContext
private val surfaceLock: ReentrantLock = ReentrantLock()
@ -109,8 +107,8 @@ class SurfaceManager(context: Context) : SurfaceHolder.Callback {
/**
* Check if current process has the capability to draw over other applications.
*
* Implementation of [Settings.canDrawOverlays] checks both context and UID,
* therefore this cannot be done in client side.
* Implementation of [Settings.canDrawOverlays] checks both context and UID, therefore this
* cannot be done in client side.
*
* @return True if current process can draw over other applications; otherwise false.
*/
@ -118,16 +116,12 @@ class SurfaceManager(context: Context) : SurfaceHolder.Callback {
return Settings.canDrawOverlays(appContext)
}
/**
* Destroy created surface.
*/
/** Destroy created surface. */
fun destroySurface() {
viewHelper.removeView()
}
/**
* Helper class that manages surface view.
*/
/** Helper class that manages surface view. */
private class ViewHelper(private val callback: SurfaceHolder.Callback) {
private var view: SurfaceView? = null
private var displayContext: Context? = null
@ -162,9 +156,7 @@ class SurfaceManager(context: Context) : SurfaceHolder.Callback {
}
}
/**
* Check whether given display is the one being used right now.
*/
/** Check whether given display is the one being used right now. */
@Suppress("DEPRECATION")
private fun isSameDisplay(context: Context, display: Display): Boolean {
val wm = context.getSystemService(Context.WINDOW_SERVICE) as WindowManager
@ -186,7 +178,7 @@ class SurfaceManager(context: Context) : SurfaceHolder.Callback {
lp.flags = if (focusable) VIEW_FLAG_FOCUSABLE else VIEW_FLAG_NOT_FOCUSABLE
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
lp.layoutInDisplayCutoutMode =
WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES;
WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES
}
val wm = context.getSystemService(Context.WINDOW_SERVICE) as WindowManager
@ -212,12 +204,11 @@ class SurfaceManager(context: Context) : SurfaceHolder.Callback {
@Suppress("DEPRECATION")
private const val VIEW_FLAG_NOT_FOCUSABLE =
WindowManager.LayoutParams.FLAG_FULLSCREEN or
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
}
}
companion object {
private const val TAG = "SurfaceManager"
}
}

View file

@ -13,9 +13,7 @@ import android.os.HandlerThread
import android.os.Message
import java.util.concurrent.atomic.AtomicInteger
/**
* Client watchdog, to determine whether runtime service should be stopped.
*/
/** Client watchdog, to determine whether runtime service should be stopped. */
class Watchdog(
private val shutdownDelayMilliseconds: Long,
private val shutdownListener: ShutdownListener
@ -25,14 +23,10 @@ class Watchdog(
* all the callbacks run on background thread.
*/
interface ShutdownListener {
/**
* Callback to be invoked when last client disconnected.
*/
/** Callback to be invoked when last client disconnected. */
fun onPrepareShutdown()
/**
* Callback to be invoked when shutdown delay ended and there's no new client connected.
*/
/** Callback to be invoked when shutdown delay ended and there's no new client connected. */
fun onShutdown()
}
@ -45,15 +39,17 @@ class Watchdog(
fun startMonitor() {
shutdownThread = HandlerThread("monado-client-watchdog")
shutdownThread.start()
shutdownHandler = object : Handler(shutdownThread.looper) {
override fun handleMessage(msg: Message) {
when (msg.what) {
MSG_SHUTDOWN -> if (clientCount.get() == 0) {
shutdownListener.onShutdown()
shutdownHandler =
object : Handler(shutdownThread.looper) {
override fun handleMessage(msg: Message) {
when (msg.what) {
MSG_SHUTDOWN ->
if (clientCount.get() == 0) {
shutdownListener.onShutdown()
}
}
}
}
}
}
fun stopMonitor() {