Android 多进程IO管理范例

原创
2022/06/11 15:20
阅读数 56

一、定义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中即可

展开阅读全文
加载中

作者的其它热门文章

打赏
0
0 收藏
分享
打赏
0 评论
0 收藏
0
分享
返回顶部
顶部