一、定义RandomgAccessFile AIDL
interface IDataTransport {
boolean open(String path, String mode);
void send(in Message msg);
void setLength(in long length);
void seek(in long length);
long length();
void close();
void writeBytes(in byte[] buffer,int offset,int size);
ParcelFileDescriptor getFileDescriptor();
}
二、实现本地接口
public interface IDataAccessFile {
void setLength(long newLength) throws IOException;
void seek(long pos) throws IOException;
long length() throws IOException;
void write(byte[] array, int i, int size) throws IOException;
FileDescriptor getFileDescriptor() throws IOException;
void close() throws IOException;
void writeBytes(String riff) throws IOException;
void writeInt(int reverseBytes) throws IOException;
void writeShortInt(int reverseBytes) throws IOException;
}
客户端aidl调用远程binder
public class DataTransportAccessFile implements IDataAccessFile {
private final File targetFile;
private final String accessMode;
private final ServiceBinder serviceBinder;
private final byte[] scratch = new byte[8];
private final boolean isOpen;
protected DataTransportAccessFile(ServiceBinder serviceBinder, File targetFile, String mode) {
this.serviceBinder = serviceBinder;
this.targetFile = targetFile;
this.accessMode = mode;
this.isOpen = this.serviceBinder.open(targetFile.getAbsolutePath(), accessMode);
}
public static IDataAccessFile createAccessFile(File targetFile, String rw) throws IOException {
if (!DataServiceManager.isSupportService()) {
return new DataRandomAccessFile(targetFile, rw);
}
ServiceBinder serviceBinder = DataServiceManager.obtainService();
if (serviceBinder == null) {
return new DataRandomAccessFile(targetFile, rw);
}
return new DataTransportAccessFile(serviceBinder, targetFile, rw);
}
@Override
public void setLength(long newLength) throws IOException {
if (!isOpen) {
return;
}
this.serviceBinder.setLength(newLength);
}
@Override
public void seek(long pos) throws IOException {
if (!isOpen) {
return;
}
this.serviceBinder.seek(pos);
}
@Override
public long length() throws IOException {
if (!isOpen) {
return targetFile.length();
}
long length = this.serviceBinder.length();
if (length == -1) {
return targetFile.length();
}
return 0;
}
@Override
public FileDescriptor getFileDescriptor() throws IOException {
if (!isOpen) {
return null;
}
ParcelFileDescriptor parcelFileDescriptor = this.serviceBinder.getFileDescriptor();
if (parcelFileDescriptor != null) {
return parcelFileDescriptor.getFileDescriptor();
}
return null;
}
@Override
public void close() throws IOException {
this.serviceBinder.close();
this.serviceBinder.shutdown();
}
@Override
public void writeBytes(String s) throws IOException {
int len = s.length();
byte[] b = new byte[len];
s.getBytes(0, len, b, 0);
writeBytes(b, 0, len);
}
@Override
public void writeInt(int v) throws IOException {
write((v >>> 24) & 0xFF);
write((v >>> 16) & 0xFF);
write((v >>> 8) & 0xFF);
write((v >>> 0) & 0xFF);
}
@Override
public void writeShortInt(int v) throws IOException {
write((v >>> 8) & 0xFF);
write((v >>> 0) & 0xFF);
}
@Override
public void write(byte[] array, int start, int len) throws IOException {
writeBytes(array, start, len);
}
public void write(int b) throws IOException {
scratch[0] = (byte) (b & 0xff);
write(scratch, 0, 1);
}
private void writeBytes(byte buffer[], int off, int len) throws IOException {
if (!isOpen) {
return;
}
this.serviceBinder.writeBytes(buffer, off, len);
}
}
为了让业务更加灵活,继续实现一个兼容RandomgAccessFile的本地版本调用
public class DataRandomAccessFile extends RandomAccessFile implements IDataAccessFile {
public DataRandomAccessFile(String name, String mode) throws FileNotFoundException {
super(name, mode);
}
public DataRandomAccessFile(File file, String mode) throws FileNotFoundException {
super(file, mode);
}
@Override
public FileDescriptor getFileDescriptor() throws IOException {
return getFD();
}
@Override
public void writeShortInt(int reverseBytes) throws IOException {
super.writeShort(reverseBytes);
}
}
三、服务管理器实现
本地需要保存Binder信息,因此先创建Binder信息类
public class ServiceBinder implements IBinder.DeathRecipient {
private static final String TAG = "ServiceBinder";
private static final int MAX_BINDER_BUFFER_SIZE = 7 * 1024;
public String serviceName;
public IDataTransport transport;
public boolean markUsed = false;
private ServiceConnection serviceConnection;
public ServiceBinder(String serviceName, IDataTransport transport, ServiceConnection serviceConnection) {
this.serviceName = serviceName;
this.transport = transport;
this.serviceConnection = serviceConnection;
try {
if (this.transport != null) {
IBinder binder = this.transport.asBinder();
if (binder != null) {
binder.linkToDeath(this, 0);
}
}
} catch (RemoteException e) {
e.printStackTrace();
}
}
public boolean isAlive() {
if (transport != null) {
IBinder binder = transport.asBinder();
if (binder != null) {
try {
return binder.isBinderAlive();
} catch (Exception e) {
e.printStackTrace();
}
}
}
return false;
}
public boolean checkAlive() {
if (transport != null) {
IBinder binder = transport.asBinder();
if (binder != null) {
try {
return binder.pingBinder();
} catch (Exception e) {
e.printStackTrace();
}
}
}
return false;
}
public void shutdown() {
Log.d(TAG, "shutdown " + serviceName + " has binderDied");
Application application = AppRuntime.getRuntimeApplication();
application.unbindService(serviceConnection);
}
@Override
public void binderDied() {
if (this.transport == null) {
return;
}
IBinder binder = this.transport.asBinder();
if (binder != null) {
binder.unlinkToDeath(this, 0);
}
this.transport = null;
DataServiceManager.unlinkToDeath(this);
Log.d(TAG, "binderDied " + serviceName);
}
public void send(Message message) {
try {
if (isAlive()) {
transport.send(message);
}
} catch (RemoteException e) {
e.printStackTrace();
} finally {
if (message != null) {
message.recycle();
}
}
}
public void setLength(long newLength) {
try {
if (isAlive()) {
transport.setLength(newLength);
}
} catch (RemoteException e) {
e.printStackTrace();
}
}
public void seek(long pos) {
try {
if (isAlive()) {
transport.seek(pos);
}
} catch (RemoteException e) {
e.printStackTrace();
}
}
public long length() {
try {
if (isAlive()) {
return transport.length();
}
} catch (RemoteException e) {
e.printStackTrace();
}
return -1;
}
public void close() {
try {
if (isAlive()) {
transport.close();
}
} catch (RemoteException e) {
e.printStackTrace();
}
}
public void writeBytes(byte[] buffer, int offset, int len) {
if(!isAlive()){
return;
}
int position = offset;
int nextWriteLength = len;
int maxLimit = 0;
ByteBuffer destBuffer = null;
try {
while (nextWriteLength > 0) {
int oldMaxLimit = maxLimit;
maxLimit = nextWriteLength > MAX_BINDER_BUFFER_SIZE ? MAX_BINDER_BUFFER_SIZE : nextWriteLength;
if (destBuffer == null || oldMaxLimit != maxLimit) {
if (destBuffer != null) {
destBuffer.recycle();
}
destBuffer = ByteBuffer.obtain(maxLimit);
}
System.arraycopy(buffer, position, destBuffer.getBuffer(), 0, maxLimit);
transport.writeBytes(destBuffer.getBuffer(), 0, maxLimit);
position = position + maxLimit;
nextWriteLength = nextWriteLength - maxLimit;
}
}catch (RemoteException e){
e.printStackTrace();
}finally {
if (destBuffer != null) {
destBuffer.recycle();
}
}
}
public ParcelFileDescriptor getFileDescriptor() {
try {
if (isAlive()) {
transport.getFileDescriptor();
}
} catch (RemoteException e) {
e.printStackTrace();
}
return null;
}
public boolean open(String path, String mode) {
try {
if (isAlive()) {
return transport.open(path,mode);
}
} catch (RemoteException e) {
e.printStackTrace();
}
return false;
}
}
实现服务管理器
public class DataServiceManager {
private static LinkedList<ServiceBinder> CACHE = new LinkedList<>();
private static ExecutorService sExecutorService;
private static volatile boolean isSupportService = false;
public static void isSupportService(boolean support) {
isSupportService = support;
}
public static final Class<? extends DataIOService>[] serviceList = new Class[]{
DataIOService1.class,
DataIOService2.class,
DataIOService3.class,
DataIOService4.class,
};
public static ServiceBinder obtainService() {
if(!isSupportService){
return null;
}
ServiceBinder selectBinder = null;
for (ServiceBinder binder : CACHE) {
if (binder.markUsed) {
continue;
}
selectBinder = binder;
break;
}
if (selectBinder != null ) {
if(selectBinder.checkAlive()) {
return selectBinder;
}
selectBinder.shutdown();
}
final Class<?> service = selectService();
if (service == null) {
return null;
}
ServiceBinder binder = getServiceBinder(service);
if (binder != null) {
binder.markUsed = true;
}
return binder;
}
private static ServiceBinder getServiceBinder(final Class<?> service) {
if (sExecutorService == null) {
sExecutorService = Executors.newCachedThreadPool();
}
final CountDownLatch countDownLatch = new CountDownLatch(1);
sExecutorService.execute(new Runnable() {
@Override
public void run() {
Application application = AppRuntime.getRuntimeApplication();
Intent intent = new Intent(application, service);
final ServiceConnection serviceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName componentName, IBinder service) {
synchronized (CACHE) {
CACHE.add(new ServiceBinder(componentName.getClassName(), IDataTransport.Stub.asInterface(service), this));
}
countDownLatch.countDown();
}
@Override
public void onServiceDisconnected(ComponentName componentName) {
ServiceBinder binder = findServiceBinder(componentName.getClassName());
if(binder!=null){
binder.binderDied();
}
countDownLatch.countDown();
}
};
try {
application.bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE);
}catch (Exception e){
e.printStackTrace();
countDownLatch.countDown();
}
}
});
try {
countDownLatch.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
ServiceBinder binder = findServiceBinder(service);
return binder;
}
public static boolean isSupportService() {
return isSupportService;
}
private static Class<?> selectService() {
synchronized (CACHE) {
for (Class<?> service : serviceList) {
ServiceBinder binder = findServiceBinder(service);
if (binder == null) {
return service;
}
}
}
return null;
}
private static ServiceBinder findServiceBinder(Class<?> service) {
return findServiceBinder(service.getName());
}
private static ServiceBinder findServiceBinder(String serviceName) {
synchronized (CACHE) {
for (ServiceBinder binder : CACHE) {
if (binder.serviceName.equals(serviceName)) {
return binder;
}
}
}
return null;
}
public static void unlinkToDeath(ServiceBinder serviceBinder) {
synchronized (CACHE) {
CACHE.remove(serviceBinder);
}
}
}
四、服务端Service实现
public abstract class DataIOService extends Service {
public static final int DEFAULT_RKCHIP_COMPATS = 1;
private final String name;
public final static int MSG_OPEN = 1;
public final static int MSG_READ = 2;
public final static int MSG_WRITE = 3;
public final static int MSG_CLOSE = 4;
public final static int MSG_WRITE_HEADR = 4;
private IDataAccessFile raf = null;
private IDataTransport transport;
protected DataIOService() {
this.name = getServiceName();
Log.d(this.name, "constructor <init>");
}
@Override
public void onCreate() {
super.onCreate();
Log.d(this.name, "onCreate");
}
@Override
public IBinder onBind(Intent intent) {
Log.d(this.name, "onBind");
if (transport == null) {
transport = getDataTransport();
}
return transport.asBinder();
}
private IDataTransport getDataTransport() {
return new IDataTransport.Stub() {
private String TAG = "PcmIOService";
RandomAccessFile raf = null;
@Override
public boolean open(String path, String mode) throws RemoteException {
try {
Log.d(TAG, "IDataTransport open="+path+",mode="+mode);
File file = new File(path);
if(!file.exists()){
file.createNewFile();
}
raf = new RandomAccessFile(path,mode);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return raf!=null;
}
@Override
public void send(Message msg) throws RemoteException {
handleMessage(msg);
}
@Override
public void setLength(long length) throws RemoteException {
try {
Log.d(TAG, "IDataTransport length");
if(raf!=null){
raf.setLength(length);
}
} catch (IOException e) {
e.printStackTrace();
RemoteException r = new RemoteException();
r.addSuppressed(e);
throw r;
}
}
@Override
public void seek(long pos) throws RemoteException {
try {
Log.d(TAG, "IDataTransport seek");
if(raf!=null){
raf.seek(pos);
}
} catch (IOException e) {
e.printStackTrace();
RemoteException r = new RemoteException();
r.addSuppressed(e);
throw r;
}
}
@Override
public long length() throws RemoteException {
try {
Log.d(TAG, "IDataTransport length");
if(raf!=null){
return raf.length();
}
} catch (IOException e) {
e.printStackTrace();
RemoteException r = new RemoteException();
r.addSuppressed(e);
throw r;
}
return -1;
}
@Override
public void close() throws RemoteException {
try {
Log.d(TAG, "IDataTransport close");
if(raf!=null){
raf.close();
}
} catch (IOException e) {
e.printStackTrace();
RemoteException r = new RemoteException();
r.addSuppressed(e);
throw r;
}
}
@Override
public void writeBytes(byte[] buffer, int offset, int size) throws RemoteException {
try {
if(raf!=null){
raf.write(buffer,offset,size);
}
} catch (IOException e) {
e.printStackTrace();
RemoteException r = new RemoteException();
r.addSuppressed(e);
throw r;
}
}
@Override
public ParcelFileDescriptor getFileDescriptor() throws RemoteException {
try {
if(raf!=null){
FileDescriptor fd = raf.getFD();
return ParcelFileDescriptor.dup(fd);
}
} catch (IOException e) {
e.printStackTrace();
RemoteException r = new RemoteException();
r.addSuppressed(e);
throw r;
}
return null;
}
};
}
@Override
public boolean onUnbind(Intent intent) {
Log.d(this.name, "onUnbind");
return super.onUnbind(intent);
}
@Override
public void onDestroy() {
Log.d(this.name, "onDestroy");
super.onDestroy();
android.os.Process.killProcess(android.os.Process.myPid());
}
public boolean handleMessage(Message msg) {
return true;
}
public abstract String getServiceName();
}
这是个抽象类,继承实现注册到manifest中即可