Commit 64b329bc authored by Ryan Pavlik's avatar Ryan Pavlik

A little bit more implementation, a lot more documentation.

parent c1f64f96
Pipeline #199531 passed with stages
in 3 minutes and 31 seconds
...@@ -15,41 +15,133 @@ import android.content.Intent; ...@@ -15,41 +15,133 @@ import android.content.Intent;
import android.content.ServiceConnection; import android.content.ServiceConnection;
import android.os.IBinder; import android.os.IBinder;
import android.os.ParcelFileDescriptor; import android.os.ParcelFileDescriptor;
import android.os.RemoteException;
import android.util.Log;
import androidx.annotation.Keep; import androidx.annotation.Keep;
import java.io.IOException; import java.io.IOException;
/**
* 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.
*/
@Keep @Keep
public class Client implements ServiceConnection { public class Client implements ServiceConnection {
private static final String TAG = "monado-ipc-client";
/**
* Context provided by app.
*/
private Context context;
/**
* Pointer to local IPC proxy: calling methods on it automatically transports arguments across binder IPC.
* <p>
* May be null!
*/
public IMonado monado; public IMonado monado;
/**
* "Our" side of the socket pair - the other side is sent to the server automatically on connection.
*/
public ParcelFileDescriptor fd; public ParcelFileDescriptor fd;
public void bind(Context context) { /**
/** * Indicates that we tried to connect but failed.
* @todo how to get the right package here? Do we have to go so far as to re-enumerate ourselves? * <p>
*/ * Used to distinguish a "not yet fully connected" null monado member from a "tried and failed"
* null monado member.
*/
public boolean failed = false;
/**
* Bind to the Monado IPC service - this asynchronously starts connecting (and launching the
* service if it's not already running)
* <p>
* The IPC client code on Android should load this class (from the right package), instantiate
* this class, 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?
* <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) {
// in case app context returned null
context = context_;
}
context.bindService( context.bindService(
new Intent("org.freedesktop.monado.CONNECT") new Intent("org.freedesktop.monado.CONNECT")
.setPackage("org.freedesktop.monado.openxr.out_of_process"), .setPackage(packageName),
this, Context.BIND_AUTO_CREATE); this, Context.BIND_AUTO_CREATE);
// does not bind right away! This takes some time. // does not bind right away! This takes some time.
} }
/**
* Some on-failure cleanup.
*/
private void handleFailure() {
failed = true;
if (context != null) context.unbindService(this);
monado = null;
}
/**
* Handle the asynchronous connection of the binder IPC.
* <p>
* This sets up the class member `monado`, as well as the member `fd`. It calls
* `IMonado.connect()` automatically. The client still needs to call `IMonado.passAppSurface()`
* on `monado`.
*
* @param name should match the intent above, but not used.
* @param service the associated service, which we cast in this function.
*/
@Override @Override
public void onServiceConnected(ComponentName name, IBinder service) { public void onServiceConnected(ComponentName name, IBinder service) {
monado = IMonado.Stub.asInterface(service); monado = IMonado.Stub.asInterface(service);
ParcelFileDescriptor theirs;
try { try {
ParcelFileDescriptor[] fds = ParcelFileDescriptor.createSocketPair(); ParcelFileDescriptor[] fds = ParcelFileDescriptor.createSocketPair();
fd = fds[0];
theirs = fds[1];
} catch (IOException e) { } catch (IOException e) {
e.printStackTrace(); e.printStackTrace();
Log.e(TAG, "could not create socket pair: " + e.toString());
handleFailure();
return;
}
try {
monado.connect(theirs);
} catch (RemoteException e) {
e.printStackTrace();
Log.e(TAG, "could not call IMonado.connect: " + e.toString());
handleFailure();
} }
} }
/**
* Handle asynchronous disconnect.
*
* @param name should match the intent above, but not used.
*/
@Override @Override
public void onServiceDisconnected(ComponentName name) { public void onServiceDisconnected(ComponentName name) {
monado = null; monado = null;
} }
/*
* @todo do we need to watch for a disconnect here?
* https://stackoverflow.com/questions/18078914/notify-an-android-service-when-a-bound-client-disconnects
*
* Our existing native disconnect handling might be sufficient.
*/
} }
...@@ -16,6 +16,11 @@ import androidx.annotation.Keep; ...@@ -16,6 +16,11 @@ import androidx.annotation.Keep;
import org.freedesktop.monado.ipc.IMonado.Stub; import org.freedesktop.monado.ipc.IMonado.Stub;
/**
* Java implementation of the IMonado IPC interface.
*
* All this does is delegate calls to native JNI implementations
*/
@Keep @Keep
public class MonadoImpl extends IMonado.Stub { public class MonadoImpl extends IMonado.Stub {
...@@ -28,15 +33,40 @@ public class MonadoImpl extends IMonado.Stub { ...@@ -28,15 +33,40 @@ public class MonadoImpl extends IMonado.Stub {
} }
/** /**
* Native handling of receiving a surface: should convert it to an ANativeWindow then do stuff
* with it.
*
* 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
* @todo figure out a good way to make the MonadoImpl pointer a client ID * @todo figure out a good way to make the MonadoImpl pointer a client ID
*/ */
private native void nativeAppSurface(Surface surface); private native void nativeAppSurface(Surface surface);
/**
* 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.
*
* 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.
*
* 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
* @todo figure out a good way to make the MonadoImpl pointer a client ID
*/
private native void nativeAddClient(ParcelFileDescriptor parcelFileDescriptor); private native void nativeAddClient(ParcelFileDescriptor parcelFileDescriptor);
static { static {
// Load the shared library with the native parts of this class // Load the shared library with the native parts of this class
// This is the service-lib target.
System.loadLibrary("monado-service"); System.loadLibrary("monado-service");
} }
} }
...@@ -15,6 +15,11 @@ import android.os.IBinder; ...@@ -15,6 +15,11 @@ import android.os.IBinder;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
/**
* Minimal implementation of a Service.
*
* This is needed so that the APK can expose the binder service implemented in MonadoImpl.
*/
public class MonadoService extends Service { public class MonadoService extends Service {
@Nullable @Nullable
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment