mirror of
https://github.com/topjohnwu/libsu.git
synced 2024-11-27 05:50:26 +00:00
Support multiple clients
This commit is contained in:
parent
a2aaf414a8
commit
d0ce4b5305
@ -28,6 +28,7 @@ interface IFileSystemService {
|
||||
/* (err, bool) */ ParcelValues createLink(String link, String target, boolean soft);
|
||||
|
||||
// I/O APIs
|
||||
oneway void register(IBinder client);
|
||||
/* (err, int) */ ParcelValues open(String path, int mode, String fifo);
|
||||
oneway void close(int handle);
|
||||
/* (err, int) */ ParcelValues pread(int handle, int len, long offset);
|
||||
|
@ -24,7 +24,10 @@ import static android.system.OsConstants.SEEK_END;
|
||||
import static android.system.OsConstants.SEEK_SET;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.os.Binder;
|
||||
import android.os.Build;
|
||||
import android.os.IBinder;
|
||||
import android.os.RemoteException;
|
||||
import android.system.ErrnoException;
|
||||
import android.system.Int64Ref;
|
||||
import android.system.Os;
|
||||
@ -42,7 +45,6 @@ import java.io.FileDescriptor;
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.channels.ClosedChannelException;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
class FileSystemService extends IFileSystemService.Stub {
|
||||
|
||||
@ -261,24 +263,74 @@ class FileSystemService extends IFileSystemService.Stub {
|
||||
}
|
||||
}
|
||||
|
||||
static class FileNotOpenException extends IOException {
|
||||
FileNotOpenException() {
|
||||
super("Requested file was not opened!");
|
||||
static class FileContainer {
|
||||
|
||||
private final static String ERROR_MSG = "Requested file was not opened!";
|
||||
|
||||
private int nextHandle = 0;
|
||||
// pid -> handle -> holder
|
||||
private final SparseArray<SparseArray<FileHolder>> files = new SparseArray<>();
|
||||
|
||||
@NonNull
|
||||
synchronized FileHolder get(int handle) throws IOException {
|
||||
int pid = Binder.getCallingPid();
|
||||
SparseArray<FileHolder> pidFiles = files.get(pid);
|
||||
if (pidFiles == null)
|
||||
throw new IOException(ERROR_MSG);
|
||||
FileHolder h = pidFiles.get(handle);
|
||||
if (h == null)
|
||||
throw new IOException(ERROR_MSG);
|
||||
return h;
|
||||
}
|
||||
|
||||
synchronized int put(FileHolder h) {
|
||||
int pid = Binder.getCallingPid();
|
||||
SparseArray<FileHolder> pidFiles = files.get(pid);
|
||||
if (pidFiles == null) {
|
||||
pidFiles = new SparseArray<>();
|
||||
files.put(pid, pidFiles);
|
||||
}
|
||||
int handle = nextHandle++;
|
||||
pidFiles.append(handle, h);
|
||||
return handle;
|
||||
}
|
||||
|
||||
synchronized void remove(int handle) {
|
||||
int pid = Binder.getCallingPid();
|
||||
SparseArray<FileHolder> pidFiles = files.get(pid);
|
||||
if (pidFiles == null)
|
||||
return;
|
||||
FileHolder h = pidFiles.get(handle);
|
||||
if (h == null)
|
||||
return;
|
||||
pidFiles.remove(handle);
|
||||
synchronized (h) {
|
||||
h.close();
|
||||
}
|
||||
}
|
||||
|
||||
synchronized void pidDied(int pid) {
|
||||
SparseArray<FileHolder> pidFiles = files.get(pid);
|
||||
if (pidFiles == null)
|
||||
return;
|
||||
files.remove(pid);
|
||||
for (int i = 0; i < pidFiles.size(); ++i) {
|
||||
FileHolder h = pidFiles.valueAt(i);
|
||||
synchronized (h) {
|
||||
h.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private final AtomicInteger nextHandle = new AtomicInteger(0);
|
||||
private final SparseArray<FileHolder> openFiles = new SparseArray<>();
|
||||
private final FileContainer openFiles = new FileContainer();
|
||||
|
||||
@NonNull
|
||||
private FileHolder getHolder(int handle) throws FileNotOpenException {
|
||||
synchronized (openFiles) {
|
||||
FileHolder h = openFiles.get(handle);
|
||||
if (h == null) {
|
||||
throw new FileNotOpenException();
|
||||
}
|
||||
return h;
|
||||
}
|
||||
@Override
|
||||
public void register(IBinder client) {
|
||||
int pid = Binder.getCallingPid();
|
||||
try {
|
||||
client.linkToDeath(() -> openFiles.pidDied(pid), 0);
|
||||
} catch (RemoteException ignored) {}
|
||||
}
|
||||
|
||||
@SuppressWarnings("OctalInteger")
|
||||
@ -286,16 +338,12 @@ class FileSystemService extends IFileSystemService.Stub {
|
||||
public ParcelValues open(String path, int mode, String fifo) {
|
||||
ParcelValues values = new ParcelValues();
|
||||
values.add(null);
|
||||
int handle = nextHandle.getAndIncrement();
|
||||
FileHolder h = new FileHolder();
|
||||
try {
|
||||
h.fd = Os.open(path, mode | O_NONBLOCK, 0666);
|
||||
h.read = Os.open(fifo, O_RDONLY | O_NONBLOCK, 0);
|
||||
h.write = Os.open(fifo, O_WRONLY | O_NONBLOCK, 0);
|
||||
synchronized (openFiles) {
|
||||
openFiles.append(handle, h);
|
||||
}
|
||||
values.add(handle);
|
||||
values.add(openFiles.put(h));
|
||||
} catch (ErrnoException e) {
|
||||
values.set(0, e);
|
||||
h.close();
|
||||
@ -305,16 +353,7 @@ class FileSystemService extends IFileSystemService.Stub {
|
||||
|
||||
@Override
|
||||
public void close(int handle) {
|
||||
final FileHolder h;
|
||||
synchronized (openFiles) {
|
||||
h = openFiles.get(handle);
|
||||
if (h == null)
|
||||
return;
|
||||
openFiles.remove(handle);
|
||||
}
|
||||
synchronized (h) {
|
||||
h.close();
|
||||
}
|
||||
openFiles.remove(handle);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -322,7 +361,7 @@ class FileSystemService extends IFileSystemService.Stub {
|
||||
ParcelValues values = new ParcelValues();
|
||||
values.add(null);
|
||||
try {
|
||||
final FileHolder h = getHolder(handle);
|
||||
final FileHolder h = openFiles.get(handle);
|
||||
final long result;
|
||||
synchronized (h) {
|
||||
h.ensureOpen();
|
||||
@ -365,7 +404,7 @@ class FileSystemService extends IFileSystemService.Stub {
|
||||
ParcelValues values = new ParcelValues();
|
||||
values.add(null);
|
||||
try {
|
||||
final FileHolder h = getHolder(handle);
|
||||
final FileHolder h = openFiles.get(handle);
|
||||
synchronized (h) {
|
||||
h.ensureOpen();
|
||||
if (!FORCE_NO_SPLICE && Build.VERSION.SDK_INT >= 28) {
|
||||
@ -408,7 +447,7 @@ class FileSystemService extends IFileSystemService.Stub {
|
||||
ParcelValues values = new ParcelValues();
|
||||
values.add(null);
|
||||
try {
|
||||
final FileHolder h = getHolder(handle);
|
||||
final FileHolder h = openFiles.get(handle);
|
||||
synchronized (h) {
|
||||
h.ensureOpen();
|
||||
values.add(Os.lseek(h.fd, offset, whence));
|
||||
@ -424,7 +463,7 @@ class FileSystemService extends IFileSystemService.Stub {
|
||||
ParcelValues values = new ParcelValues();
|
||||
values.add(null);
|
||||
try {
|
||||
final FileHolder h = getHolder(handle);
|
||||
final FileHolder h = openFiles.get(handle);
|
||||
synchronized (h) {
|
||||
h.ensureOpen();
|
||||
long cur = Os.lseek(h.fd, 0, SEEK_CUR);
|
||||
@ -443,7 +482,7 @@ class FileSystemService extends IFileSystemService.Stub {
|
||||
ParcelValues values = new ParcelValues();
|
||||
values.add(null);
|
||||
try {
|
||||
final FileHolder h = getHolder(handle);
|
||||
final FileHolder h = openFiles.get(handle);
|
||||
synchronized (h) {
|
||||
h.ensureOpen();
|
||||
Os.ftruncate(h.fd, length);
|
||||
@ -459,7 +498,7 @@ class FileSystemService extends IFileSystemService.Stub {
|
||||
ParcelValues values = new ParcelValues();
|
||||
values.add(null);
|
||||
try {
|
||||
final FileHolder h = getHolder(handle);
|
||||
final FileHolder h = openFiles.get(handle);
|
||||
synchronized (h) {
|
||||
h.ensureOpen();
|
||||
if (metaData)
|
||||
|
@ -16,8 +16,10 @@
|
||||
|
||||
package com.topjohnwu.superuser.internal;
|
||||
|
||||
import android.os.Binder;
|
||||
import android.os.Build;
|
||||
import android.os.IBinder;
|
||||
import android.os.RemoteException;
|
||||
import android.system.ErrnoException;
|
||||
import android.system.OsConstants;
|
||||
|
||||
@ -91,10 +93,13 @@ public final class NIOFactory {
|
||||
};
|
||||
}
|
||||
|
||||
public static FileSystemManager createRemote(IBinder b) {
|
||||
return new FileSystemManager() {
|
||||
final IFileSystemService fs = IFileSystemService.Stub.asInterface(b);
|
||||
public static FileSystemManager createRemote(IBinder b) throws RemoteException {
|
||||
IFileSystemService fs = IFileSystemService.Stub.asInterface(b);
|
||||
if (fs == null || !IFileSystemService.DESCRIPTOR.equals(b.getInterfaceDescriptor()))
|
||||
throw new IllegalArgumentException("The IBinder provided is invalid");
|
||||
|
||||
fs.register(new Binder());
|
||||
return new FileSystemManager() {
|
||||
@NonNull
|
||||
@Override
|
||||
public ExtendedFile newFile(@NonNull String pathname) {
|
||||
|
@ -22,6 +22,7 @@ import android.os.Binder;
|
||||
import android.os.Bundle;
|
||||
import android.os.IBinder;
|
||||
import android.os.ParcelFileDescriptor;
|
||||
import android.os.RemoteException;
|
||||
|
||||
import androidx.annotation.IntDef;
|
||||
import androidx.annotation.NonNull;
|
||||
@ -117,9 +118,10 @@ public abstract class FileSystemManager {
|
||||
* Calling these APIs will throw {@link UnsupportedOperationException}.
|
||||
*
|
||||
* @param binder a remote proxy of the {@link Binder} obtained from {@link #getService()}
|
||||
* @throws RemoteException if the remote process has died.
|
||||
*/
|
||||
@NonNull
|
||||
public static FileSystemManager getRemote(@NonNull IBinder binder) {
|
||||
public static FileSystemManager getRemote(@NonNull IBinder binder) throws RemoteException {
|
||||
return NIOFactory.createRemote(binder);
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user