mirror of
https://gitlab.freedesktop.org/monado/monado.git
synced 2025-03-03 21:26:36 +00:00
ipc/android: Add a blocking connect Java method, and small clean-ups.
This commit is contained in:
parent
04318b4104
commit
3011e3c9f6
src/xrt/ipc/android/src/main
|
@ -5,7 +5,11 @@
|
|||
SPDX-License-Identifier: BSL-1.0
|
||||
-->
|
||||
<application>
|
||||
<service android:name=".MonadoService" android:enabled="true" android:exported="true" android:externalService="true">
|
||||
<service
|
||||
android:name=".MonadoService"
|
||||
android:enabled="true"
|
||||
android:exported="true"
|
||||
android:externalService="true">
|
||||
<intent-filter>
|
||||
<action android:name="org.freedesktop.monado.CONNECT" />
|
||||
</intent-filter>
|
||||
|
|
|
@ -21,6 +21,8 @@ import android.util.Log;
|
|||
|
||||
import androidx.annotation.Keep;
|
||||
|
||||
import org.freedesktop.monado.auxiliary.NativeCounterpart;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
|
@ -31,49 +33,103 @@ import java.io.IOException;
|
|||
@Keep
|
||||
public class Client implements ServiceConnection {
|
||||
private static final String TAG = "monado-ipc-client";
|
||||
|
||||
/**
|
||||
* Context provided by app.
|
||||
* Used to block native until we have our side of the socket pair.
|
||||
*/
|
||||
private Context context;
|
||||
|
||||
private final Object connectSync = new Object();
|
||||
/**
|
||||
* Pointer to local IPC proxy: calling methods on it automatically transports arguments across binder IPC.
|
||||
* <p>
|
||||
* May be null!
|
||||
*/
|
||||
public IMonado monado;
|
||||
|
||||
/**
|
||||
* "Our" side of the socket pair - the other side is sent to the server automatically on connection.
|
||||
*/
|
||||
public ParcelFileDescriptor fd;
|
||||
|
||||
@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.
|
||||
*/
|
||||
@Keep
|
||||
public boolean failed = false;
|
||||
/**
|
||||
* Keep track of the ipc_client_android instance over on the native side.
|
||||
*/
|
||||
private final NativeCounterpart nativeCounterpart;
|
||||
/**
|
||||
* "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.
|
||||
*/
|
||||
private Context context;
|
||||
|
||||
/**
|
||||
* Bind to the Monado IPC service - this asynchronously starts connecting (and launching the
|
||||
* service if it's not already running)
|
||||
* Constructor
|
||||
*
|
||||
* @param nativePointer the corresponding native object's pointer.
|
||||
*/
|
||||
@Keep
|
||||
public Client(long nativePointer) {
|
||||
this.nativeCounterpart = new NativeCounterpart(nativePointer);
|
||||
this.nativeCounterpart.markAsUsedByNativeCode();
|
||||
}
|
||||
|
||||
/**
|
||||
* Let the native code notify us that it is no longer using this class.
|
||||
*/
|
||||
@Keep
|
||||
public void markAsDiscardedByNative() {
|
||||
nativeCounterpart.markAsDiscardedByNative(TAG);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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, and call this method.
|
||||
* this class (retaining a reference to it!), and call this method.
|
||||
*
|
||||
* @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.
|
||||
* (Often "org.freedesktop.monado.openxr.out_of_process" for now, at least)
|
||||
* @todo how to get the right package name here? Do we have to go so far as to re-enumerate ourselves?
|
||||
* 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.
|
||||
*/
|
||||
@Keep
|
||||
public int blockingConnect(Context context_, String packageName) {
|
||||
synchronized (connectSync) {
|
||||
bind(context_, packageName);
|
||||
try {
|
||||
while (fd == null) {
|
||||
connectSync.wait();
|
||||
}
|
||||
} catch (InterruptedException e) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return fd.getFd();
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 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.
|
||||
*/
|
||||
public void bind(Context context_, String packageName) {
|
||||
context = context_.getApplicationContext();
|
||||
if (context == null) {
|
||||
|
@ -110,9 +166,10 @@ public class Client implements ServiceConnection {
|
|||
public void onServiceConnected(ComponentName name, IBinder service) {
|
||||
monado = IMonado.Stub.asInterface(service);
|
||||
ParcelFileDescriptor theirs;
|
||||
ParcelFileDescriptor ours;
|
||||
try {
|
||||
ParcelFileDescriptor[] fds = ParcelFileDescriptor.createSocketPair();
|
||||
fd = fds[0];
|
||||
ours = fds[0];
|
||||
theirs = fds[1];
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
|
@ -126,6 +183,10 @@ public class Client implements ServiceConnection {
|
|||
e.printStackTrace();
|
||||
Log.e(TAG, "could not call IMonado.connect: " + e.toString());
|
||||
handleFailure();
|
||||
return;
|
||||
}
|
||||
synchronized (connectSync) {
|
||||
fd = ours;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -137,6 +198,7 @@ public class Client implements ServiceConnection {
|
|||
@Override
|
||||
public void onServiceDisconnected(ComponentName name) {
|
||||
monado = null;
|
||||
//! @todo tell native that the world is crumbling, then close the fd here.
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -15,18 +15,25 @@ import android.view.Surface;
|
|||
|
||||
import androidx.annotation.Keep;
|
||||
|
||||
import org.freedesktop.monado.ipc.IMonado.Stub;
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
@SuppressWarnings("JavaJniMissingFunction")
|
||||
@Keep
|
||||
public class MonadoImpl extends IMonado.Stub {
|
||||
|
||||
static {
|
||||
// Load the shared library with the native parts of this class
|
||||
// This is the service-lib target.
|
||||
System.loadLibrary("monado-service");
|
||||
}
|
||||
|
||||
public void connect(ParcelFileDescriptor parcelFileDescriptor) {
|
||||
nativeAddClient(parcelFileDescriptor);
|
||||
nativeAddClient(parcelFileDescriptor.detachFd());
|
||||
}
|
||||
|
||||
public void passAppSurface(Surface surface) {
|
||||
|
@ -36,13 +43,13 @@ public class MonadoImpl extends IMonado.Stub {
|
|||
/**
|
||||
* Native handling of receiving a surface: should convert it to an ANativeWindow then do stuff
|
||||
* with it.
|
||||
*
|
||||
* <p>
|
||||
* Ignore Android Studio complaining that this function is missing: it is not, it is just in a
|
||||
* different module. See `src/xrt/targets/service-lib/lib.cpp` for the implementation.
|
||||
* (Ignore the warning saying that file isn't included in the build: it is, Android Studio
|
||||
* is just confused.)
|
||||
*
|
||||
* @param surface
|
||||
* @param surface The surface to pass to native code
|
||||
* @todo figure out a good way to make the MonadoImpl pointer a client ID
|
||||
*/
|
||||
private native void nativeAppSurface(Surface surface);
|
||||
|
@ -50,24 +57,18 @@ 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
|
||||
* 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 Android Studio complaining that this function is missing: it is not, it is just in a
|
||||
* different module. See `src/xrt/targets/service-lib/lib.cpp` for the implementation.
|
||||
* (Ignore the warning saying that file isn't included in the build: it is, Android Studio
|
||||
* is just confused.)
|
||||
*
|
||||
* @param surface
|
||||
* @param fd The incoming file descriptor: ownership is transferred to native code here.
|
||||
* @todo figure out a good way to make the MonadoImpl pointer a client ID
|
||||
*/
|
||||
private native void nativeAddClient(ParcelFileDescriptor parcelFileDescriptor);
|
||||
|
||||
static {
|
||||
// Load the shared library with the native parts of this class
|
||||
// This is the service-lib target.
|
||||
System.loadLibrary("monado-service");
|
||||
}
|
||||
private native void nativeAddClient(int fd);
|
||||
}
|
||||
|
|
|
@ -18,7 +18,7 @@ import androidx.annotation.Nullable;
|
|||
|
||||
/**
|
||||
* Minimal implementation of a Service.
|
||||
*
|
||||
* <p>
|
||||
* This is needed so that the APK can expose the binder service implemented in MonadoImpl.
|
||||
*/
|
||||
public class MonadoService extends Service {
|
||||
|
|
Loading…
Reference in a new issue