转自:https://www.jianshu.com/p/ed87b12dfe0d
跨进程通信要求把方法调用及其数据分解至操作系统可以识别的程度,并将其从本地进程和地址空间传输至远程进程和地址空间,然后在远程进程中重新组装并执行该调用。
然后,返回值将沿相反方向传输回来。
Android 为我们提供了以下几种进程通信机制(供开发者使用的进程通信 API)对应的文章链接如下:
文件
AIDL (基于 Binder)
Binder
Messenger (基于 Binder)
ContentProvider (基于 Binder)
Socket
在上述通信机制的基础上,我们只需集中精力定义和实现 RPC 编程接口即可。
这里再对比总结一下:
AIDL
Binder
创建接口Messenger
来实现接口ContentProvider
Socket
image.png
android IPC的核心方式是binder,但是android binder的传输限制1M(被很多进程共享),在较大数据交换一般通过文件,但是效率很低,因此介绍下新的内存共享方式:
ShareMemory
通过binder把MemoryFile的ParcelFileDescriptor 传到Service;
在服务端通过ParcelFileDescriptor 读取共享内存数据;
package com.yinlib.client;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.IBinder;
import android.os.MemoryFile;
import android.os.ParcelFileDescriptor;
import android.util.Log;
import com.yinlib.service.aidl.IRemoteService;
import java.io.FileDescriptor;
import java.lang.reflect.Method;
import java.util.Arrays;
/**
* Created by jayzwang on 7/12/18.
*/
public class LocalClient {
public static final String TAG = LocalClient.class.getSimpleName();
public static final String SERVICE_ACTION = "com.yinlib.service.remoteservice";
public static final String SERVICE_PACKAGE = "com.yinlib.service";
private IRemoteService Client ;
private Context mContext;
private boolean mHasBind;
private IServiceListener mServiceListener;
private MemoryFile mServiceShareMemory;
private FileDescriptor mServiceShareFile;
private ParcelFileDescriptor mParceServiceShareFile;
private int mFD = -1;
int CONTENT_SIZE = 640*480;
// int CONTENT_SIZE = 200;
private byte[] mContent = new byte[CONTENT_SIZE];
private byte[] mContentCopy = new byte[CONTENT_SIZE];
public interface IServiceListener{
void onServiceConnect();
void onServiceDisconnect();
}
public LocalClient(Context context) {
mContext = context.getApplicationContext();
createMemFile();
}
private void createMemFile(){
try {
mServiceShareMemory = new MemoryFile("com.yinlib.service" + System.currentTimeMillis(), mContent.length);
Method method = MemoryFile.class.getDeclaredMethod("getFileDescriptor");
FileDescriptor fd = (FileDescriptor) method.invoke(mServiceShareMemory);
mParceServiceShareFile = ParcelFileDescriptor.dup(fd);
if(mServiceShareMemory != null){
mServiceShareMemory.allowPurging(false);
}
}catch (Exception e){
e.printStackTrace();
}
}
//connect to arservice, call onStart
public boolean connectService(){
boolean isBindService = mContext.getApplicationContext().bindService(new Intent(SERVICE_ACTION).setPackage(SERVICE_PACKAGE), mServiceConnect, Context.BIND_AUTO_CREATE | Context.BIND_IMPORTANT | Context.BIND_WAIVE_PRIORITY | Context.BIND_ABOVE_CLIENT);
Log.d(TAG,"bind services isBindService : " + isBindService);
return isBindService;
}
//disconnet service, call onDestroy
public void disConnectService(){
if(!mHasBind){
return;
}
mContext.unbindService(mServiceConnect);
mHasBind = false;
}
public void setServiceListener(IServiceListener listener){
mServiceListener = listener;
}
public void dataFlow(int value){
Arrays.fill(mContent, (byte)value);
if(mHasBind){
try {
Log.d(TAG, "Client dataFlow start mContent: " + mContent[0]);
long time = System.currentTimeMillis();
mServiceShareMemory.writeBytes(mContent,0,0, mContent.length);
Log.d(TAG, "Client dataFlow start mContentCopy: " + mContentCopy[0]);
Log.d(TAG, "Client dataFlow writeBytes : " + (System.currentTimeMillis()- time));
Client .dataFlow(mParceServiceShareFile, mContent.length);
Log.d(TAG, "Client dataFlow create and flowTime : " + (System.currentTimeMillis()- time));
time = System.currentTimeMillis();
Log.d(TAG, "Client dataFlow release : " + (System.currentTimeMillis()- time));
}catch (Exception e){
e.printStackTrace();
}
}
}
public int getStatus(){
int status = 0;
if(mHasBind){
try {
status = Client .getStatus();
Log.d(TAG, "Client getStatus : " + status);
}catch (Exception e){
e.printStackTrace();
}
}
return status;
}
private ServiceConnection mServiceConnect = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
Client = IRemoteService.Stub.asInterface(iBinder);
mHasBind = true;
Log.d(TAG, "onServiceConnected");
onConnect();
}
@Override
public void onServiceDisconnected(ComponentName componentName) {
mHasBind = false;
Log.d(TAG, "onServiceDisconnected");
onDisonnect();
}
};
private void onConnect(){
if(mServiceListener == null){
return;
}
mServiceListener.onServiceConnect();
}
private void onDisonnect(){
releaseShareMemory();
if(mServiceListener == null){
return;
}
mServiceListener.onServiceDisconnect();
}
private void releaseShareMemory(){
try {
mParceServiceShareFile.close();
}catch (Exception e){
e.printStackTrace();
}
if(mServiceShareMemory == null){
return;
}
mServiceShareMemory.close();
mServiceShareMemory = null;
}
@Override
protected void finalize() throws Throwable {
super.finalize();
releaseShareMemory();
}
}
package com.yinlib.service;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.os.MemoryFile;
import android.os.Parcel;
import android.os.ParcelFileDescriptor;
import android.os.RemoteException;
import android.support.annotation.Nullable;
import android.util.Log;
import com.yinlib.service.aidl.IRemoteService;
import com.yinlib.service.util.MemoryFileHelper;
/**
* $todo$
*
* @user Jay Wang
* @date 2018-07-31 11:31
*/
public class RemoteService extends Service {
public static final String TAG = RemoteService.class.getSimpleName();
private byte[] mPackageContent;
@Nullable
@Override
public IBinder onBind(Intent intent) {
return new RemoteServiceBind();
}
private void createBufferIfNeed(int length){
if(length <= 0){
Log.d(TAG, "createBufferIfNeed length <= 0");
}
if(mPackageContent != null && mPackageContent.length == length){
return ;
}
mPackageContent = new byte[length];
}
public class RemoteServiceBind extends IRemoteService.Stub
{
public RemoteServiceBind() {
super();
}
@Override
public IBinder asBinder() {
return super.asBinder();
}
@Override
public boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws
RemoteException {
return super.onTransact(code, data, reply, flags);
}
@Override
public void dataFlow(ParcelFileDescriptor data, int length) throws RemoteException {
try {
long time = System.currentTimeMillis();
createBufferIfNeed(length);
MemoryFile memoryFile = MemoryFileHelper.openMemoryFile(data, mPackageContent.length, MemoryFileHelper.OPEN_READWRITE);
memoryFile.readBytes(mPackageContent, 0, 0, mPackageContent.length);
memoryFile.close();
Log.d(TAG, "Service dataFlow data: " + mPackageContent[mPackageContent.length - 1] + " time : " + (System.currentTimeMillis() - time));
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public int getStatus() throws RemoteException {
Log.d(TAG, "Service getStatus");
return 1;
}
}
}
package com.yinlib.service.util;
import android.os.Build;
import android.os.MemoryFile;
import android.os.ParcelFileDescriptor;
import java.io.FileDescriptor;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.nio.ByteBuffer;
/**
* 对memoryFile类的扩展
* 1.从memoryFile对象中获取FileDescriptor,ParcelFileDescriptor
* 2.根据一个FileDescriptor和文件length实例化memoryFile对象
* Created by wangguijie on 2018/7/30.
*/
public class MemoryFileHelper {
/**
* 创建共享内存对象
* @param name 描述共享内存文件名称
* @param length 用于指定创建多大的共享内存对象
* @return MemoryFile 描述共享内存对象
*/
public static MemoryFile createMemoryFile(String name, int length){
try {
return new MemoryFile(name,length);
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
public static MemoryFile openMemoryFile(ParcelFileDescriptor pfd, int length, int mode){
if(pfd == null){
throw new IllegalArgumentException("ParcelFileDescriptor is null");
}
FileDescriptor fd = pfd.getFileDescriptor();
return openMemoryFile(fd,length,mode);
}
private static final int PROT_READ = 0x1;
private static final int PROT_WRITE = 0x2;
public static final int OPEN_READONLY = PROT_READ;
public static final int OPEN_READWRITE = PROT_READ |PROT_WRITE;
/**
* 打开共享内存,一般是一个地方创建了一块共享内存
* 另一个地方持有描述这块共享内存的文件描述符,调用
* 此方法即可获得一个描述那块共享内存的MemoryFile
* 对象
* @param fd 文件描述
* @param length 共享内存的大小
* @param mode PROT_READ = 0x1只读方式打开,
* PROT_WRITE = 0x2可写方式打开,
* PROT_WRITE|PROT_READ可读可写方式打开
* @return MemoryFile
*/
public static MemoryFile openMemoryFile(FileDescriptor fd,int length,int mode){
if (mode != OPEN_READONLY && mode != OPEN_READWRITE)
throw new IllegalArgumentException("invalid mode, only support OPEN_READONLY and OPEN_READWRITE");
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.O) {
return openMemoryFileV26(fd, length, mode);
}
return openMemoryFileV27(fd, mode);
}
private static MemoryFile openMemoryFileV27(FileDescriptor fd, int mode) {
MemoryFile memoryFile = null;
try {
memoryFile = new MemoryFile("service.remote",1);
memoryFile.close();
Class> c = Class.forName("android.os.SharedMemory");
Object sharedMemory = InvokeUtil.newInstanceOrThrow(c,fd);
//SharedMemory sm;
ByteBuffer mapping = null;
if (mode == OPEN_READONLY) {
mapping = (ByteBuffer) InvokeUtil.invokeMethod(sharedMemory, "mapReadOnly");
} else {
mapping = (ByteBuffer) InvokeUtil.invokeMethod(sharedMemory, "mapReadWrite");
}
InvokeUtil.setValueOfField(memoryFile, "mSharedMemory", sharedMemory);
InvokeUtil.setValueOfField(memoryFile, "mMapping",mapping);
return memoryFile;
} catch (Exception e) {
throw new RuntimeException("openMemoryFile failed!", e);
}
}
public static MemoryFile openMemoryFileV26(FileDescriptor fd,int length,int mode){
MemoryFile memoryFile = null;
try {
memoryFile = new MemoryFile("service.remote",1);
memoryFile.close();
Class> c = MemoryFile.class;
InvokeUtil.setValueOfField(memoryFile, "mFD", fd);
InvokeUtil.setValueOfField(memoryFile, "mLength",length);
long address = (long) InvokeUtil.invokeStaticMethod(c, "native_mmap", fd, length, mode);
InvokeUtil.setValueOfField(memoryFile,"mAddress", address);
} catch (Exception e) {
e.printStackTrace();
}
return memoryFile;
}
/**
* 获取memoryFile的ParcelFileDescriptor
* @param memoryFile 描述一块共享内存
* @return ParcelFileDescriptor
*/
public static ParcelFileDescriptor getParcelFileDescriptor(MemoryFile memoryFile) {
if(memoryFile == null){
throw new IllegalArgumentException("memoryFile is null");
}
ParcelFileDescriptor pfd = null;
try {
FileDescriptor fd = getFileDescriptor(memoryFile);
pfd = (ParcelFileDescriptor) InvokeUtil.newInstanceOrThrow(ParcelFileDescriptor.class, fd);
return pfd;
} catch (Exception e) {
throw new RuntimeException("InvokeUtil.newInstanceOrThrow failed", e);
}
}
/**
* 获取memoryFile的FileDescriptor
* @param memoryFile 描述一块共享内存
* @return 这块共享内存对应的文件描述符
*/
public static FileDescriptor getFileDescriptor(MemoryFile memoryFile) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
if(memoryFile == null){
throw new IllegalArgumentException("memoryFile is null");
}
FileDescriptor fd;
fd = (FileDescriptor) InvokeUtil.invokeMethod(memoryFile, "getFileDescriptor");
return fd;
}
}
package com.yinlib.service.util;
import android.text.TextUtils;
import android.util.Log;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.List;
import java.util.NoSuchElementException;
/**
* 反映工具类
* Created by wangguijie
*/
public final class InvokeUtil {
private static final String TAG = "InvokeUtil";
public static T newEmptyInstance(Class extends T> paramClass)
{
try
{
return newEmptyInstanceOrThrow(paramClass);
}
catch (Exception localException)
{
Log.w(TAG, "Meet exception when make instance as a " + paramClass.getSimpleName(),
localException);
}
return null;
}
private static Object getDefaultValue(Class> paramClass)
{
if ((Integer.TYPE.equals(paramClass)) || (Integer.class.equals(paramClass))
|| (Byte.TYPE.equals(paramClass)) || (Byte.class.equals(paramClass))
|| (Short.TYPE.equals(paramClass)) || (Short.class.equals(paramClass))
|| (Long.TYPE.equals(paramClass)) || (Long.class.equals(paramClass))
|| (Double.TYPE.equals(paramClass)) || (Double.class.equals(paramClass))
|| (Float.TYPE.equals(paramClass)) || (Float.class.equals(paramClass)))
return Integer.valueOf(0);
if ((Boolean.TYPE.equals(paramClass)) || (Boolean.class.equals(paramClass)))
return Boolean.valueOf(false);
if ((Character.TYPE.equals(paramClass)) || (Character.class.equals(paramClass)))
return Character.valueOf('\000');
return null;
}
public static T newEmptyInstanceOrThrow(Class extends T> paramClass) throws IllegalAccessException,
InvocationTargetException, InstantiationException {
int i = 0;
Constructor[] constructors = paramClass.getDeclaredConstructors();
if ((constructors == null) || (constructors.length == 0))
throw new IllegalArgumentException("Can't get even one available constructor for " + paramClass);
for (Constructor constructor: constructors) {
constructor.setAccessible(true);
Class[] arrayOfClass = constructor.getParameterTypes();
if ((arrayOfClass == null) || (arrayOfClass.length == 0)) {
return (T) constructor.newInstance(new Object[0]);
}
}
Constructor localConstructor = constructors[0];
localConstructor.setAccessible(true);
Class[] paramClasses = localConstructor.getParameterTypes();
Object[] params = new Object[paramClasses.length];
while (i < paramClasses.length)
{
params[i] = getDefaultValue(paramClasses[i]);
i++;
}
return (T) localConstructor.newInstance(params);
}
public static T newInstanceOrThrow(Class extends T> clz, Object...params) throws IllegalAccessException,
InvocationTargetException, InstantiationException {
Constructor[] constructors = clz.getDeclaredConstructors();
if ((constructors == null) || (constructors.length == 0))
throw new IllegalArgumentException("Can't get even one available constructor for " + clz);
Class[] paramClasses = new Class[params.length];
Constructor found = null;
for (Constructor constructor: constructors) {
Class[] arrayOfClass = constructor.getParameterTypes();
if (arrayOfClass.length != params.length)
continue;
if (params.length == 0) {
found = constructor;
break;
}
boolean matched = true;
for (int i = 0; i < params.length; i++) {
int v = instanceOf(params[0], arrayOfClass[i]);
if (v == INSTANCE_DENIED) {
matched = false;
break;
}
}
if (matched) {
found = constructor;
break;
}
}
if (found != null) {
found.setAccessible(true);
return (T) found.newInstance(params);
}
throw new NoSuchElementException("no Constructor match it!!");
}
public static Object invokeMethod(Object o, String methodName, Object...params)
throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
Method method = matchMethod(o.getClass(), methodName, params);
if (method == null)
throw new NoSuchMethodException("class " + o.getClass().getCanonicalName() +
" cannot find method " + methodName);
Object out = method.invoke(o, params);
return out;
}
public static Object invokeStaticMethod(String className, String methodName, Object...params)
throws NoSuchMethodException, InvocationTargetException, IllegalAccessException, ClassNotFoundException {
Class clz = Class.forName(className);
Method method = matchMethod(clz, methodName, params);
if (method == null)
throw new NoSuchMethodException("class " + className +
" cannot find method " + methodName);
Object out = method.invoke(null, params);
return out;
}
public static Object invokeStaticMethod(Class clz, String methodName, Object...params)
throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
Method method = matchMethod(clz, methodName, params);
if (method == null)
throw new NoSuchMethodException("class " + clz.getCanonicalName() +
" cannot find method " + methodName);
Object out = method.invoke(null, params);
return out;
}
private static Class getObjectClass(Object o) {
Class clz = o.getClass();
Class inner = wrappedClass(clz);
if (inner != null && inner.isPrimitive()) {
return inner;
}
return clz;
}
public static boolean isWrapClass(Class clz) {
Class inner = wrappedClass(clz);
if (inner != null)
return inner.isPrimitive();
return false;
}
public static Class wrappedClass(Class clz) {
try {
return ((Class) clz.getField("TYPE").get(null));
} catch (Exception e) {
return null;
}
}
public static Method[] methodsForName(Class clz, String name) {
Method[] methods = clz.getDeclaredMethods();
if (methods == null || methods.length == 0)
return null;
List out = new ArrayList<>();
for (Method method: methods) {
if (method.getName().equals(name)) {
out.add(method);
}
}
if (out.size() == 0)
return null;
return out.toArray(new Method[0]);
}
public static Method matchMethod(Class clz, String name, Object...params) {
Method[] methods = methodsForName(clz, name);
if (methods == null || methods.length == 0)
return null;
Method found = null;
int maxMatch = 0;
for (Method method: methods) {
int v = matchMethodParameterTypes(method, params);
if ( v > maxMatch) {
maxMatch = v;
found = method;
}
}
if (maxMatch == METHOD_MATCH_NONE)
return null;
if ((maxMatch & METHOD_MATCH_PUBLIC) == 0 ) {
found.setAccessible(true);
}
return found;
}
private final static int INSTANCE_DENIED = 0;
private final static int INSTANCE_OK = 1;
private final static int INSTANCE_CONV = 2;
private static int instanceOf(Object o, Class> clz) {
if ( o == null ) {
// 基本类型不允许null对象
if (clz.isPrimitive()) return INSTANCE_DENIED;
// 空对象可匹配任何对象类型
return INSTANCE_OK;
}
if (clz.isPrimitive()) {
if (clz == void.class)
return INSTANCE_DENIED;
Class wclz = wrappedClass(o.getClass());
// 非封装类型对象
if (wclz == null)
return INSTANCE_DENIED;
// 基本类型与封装类型完全匹配
if (wclz == clz)
return INSTANCE_OK;
// 基本类型与封装类型完全不匹配
if (clz == long.class && wclz == int.class)
return INSTANCE_CONV;
if (clz == double.class && (wclz == float.class || wclz == long.class || wclz == int.class) )
return INSTANCE_CONV;
if (clz == float.class && wclz == int.class)
return INSTANCE_CONV;
if (clz == int.class && (wclz == byte.class || wclz == short.class || wclz == char.class) )
return INSTANCE_CONV;
return INSTANCE_DENIED;
}
return clz.isInstance(o)?INSTANCE_OK: INSTANCE_DENIED;
}
private final static int METHOD_MATCH_NONE = 0;
private final static int METHOD_MATCH_PUBLIC = 0x01;
private final static int METHOD_MATCH_PARAMS_TYPE = 0x02;
private final static int METHOD_MATCH_STRICTLY = METHOD_MATCH_PUBLIC | METHOD_MATCH_PARAMS_TYPE;
private static int matchMethodParameterTypes(Method method, Object...params) {
Class[] types = method.getParameterTypes();
int tlen = ArrayUtils.length(types);
int plen = ArrayUtils.length(params);
int value = METHOD_MATCH_NONE;
if (tlen != plen) {
return METHOD_MATCH_NONE;
}
if (plen > 0) {
int[] pos = new int[plen];
int size = 0;
for (int i= 0; i< plen; i++) {
Object p = params[i];
int v = instanceOf(p, types[i]);
if (v == INSTANCE_DENIED) {
return METHOD_MATCH_NONE;
}
else if (v == INSTANCE_OK)
continue;
else
pos[size++] = i;
}
if (size > 0) {
for (int index: pos) {
Object p = params[index];
if (p instanceof Number) {
Number n = (Number) p;
if (types[index] == int.class) {
params[index] = n.intValue();
}
else if (types[index] == long.class) {
params[index] = n.longValue();
}
else if (types[index] == double.class) {
params[index] = n.doubleValue();
}
else if (types[index] == float.class) {
params[index] = n.floatValue();
}
else if (types[index] == byte.class) {
params[index] = n.byteValue();
}
else if (types[index] == short.class) {
params[index] = n.shortValue();
}
}
else if (p instanceof Character) {
char c = (Character)p;
if (types[index] == int.class) {
params[index] = (int)c;
}
else if (types[index] == long.class) {
params[index] = (long)c;
}
else if (types[index] == byte.class) {
params[index] = (byte)c;
}
else if (types[index] == short.class) {
params[index] = (short)c;
}
}
}
}
}
value |= METHOD_MATCH_PARAMS_TYPE;
if (Modifier.isPublic(method.getModifiers())) {
value |= METHOD_MATCH_PUBLIC;
}
return value;
}
public static Object valueOfField(Object o, String fieldName) throws NoSuchFieldException, IllegalAccessException {
if (TextUtils.isEmpty(fieldName))
throw new IllegalArgumentException("param fieldName is empty");
Class clz = o.getClass();
Field field = fieldByNameRecursive(clz, fieldName);
if (!Modifier.isPublic (field.getModifiers()) ) {
field.setAccessible(true);
}
return field.get(o);
}
@SuppressWarnings("unchecked")
public static Object valueOfField(T o, Class superClass, String fieldName) throws NoSuchFieldException, IllegalAccessException {
if (TextUtils.isEmpty(fieldName))
throw new IllegalArgumentException("param fieldName is empty");
Class clz = o.getClass();
if (superClass == null)
superClass = clz;
else if (!superClass.isAssignableFrom(clz))
throw new IllegalArgumentException("superClass not match the object o " + clz.getCanonicalName());
Field field = superClass.getDeclaredField(fieldName);
if (!Modifier.isPublic (field.getModifiers()) ) {
field.setAccessible(true);
}
return field.get(o);
}
public static Object valueOfStaticField(Class clz, String fieldName) throws NoSuchFieldException, IllegalAccessException {
if (TextUtils.isEmpty(fieldName))
throw new IllegalArgumentException("param fieldName is empty");
Field field = fieldByNameRecursive(clz, fieldName);
if (!Modifier.isPublic (field.getModifiers()) ) {
field.setAccessible(true);
}
return field.get(null);
}
public static void setValueOfField(Object o, String fieldName, Object value) throws NoSuchFieldException,
IllegalAccessException {
if (TextUtils.isEmpty(fieldName))
throw new IllegalArgumentException("param fieldName is empty");
Class clz = o.getClass();
Field field = fieldByNameRecursive(clz, fieldName);
if (!Modifier.isPublic (field.getModifiers()) || Modifier.isFinal(field.getModifiers())) {
field.setAccessible(true);
}
field.set(o, value);
}
public static void setStaticValueOfField(Class clz, String fieldName, Object value) throws NoSuchFieldException,
IllegalAccessException {
if (TextUtils.isEmpty(fieldName))
throw new IllegalArgumentException("param fieldName is empty");
Field field = fieldByNameRecursive(clz, fieldName);
if (!Modifier.isPublic (field.getModifiers()) || Modifier.isFinal(field.getModifiers())) {
field.setAccessible(true);
}
field.set(null, value);
}
public static Field[] fieldsByClassRecursive(Class clz, Class memberClz) throws NoSuchFieldException {
Class target = clz;
ArrayList all = null;
while (!target.equals(Object.class)) {
Field[] fields = target.getDeclaredFields();
if (!ArrayUtils.empty(fields)) {
for (Field field: fields) {
if (field.getDeclaringClass().equals(memberClz)) {
if (all == null)
all = new ArrayList<>();
all.add(field);
}
}
}
target = clz.getSuperclass();
}
if (CollectionUtils.isEmpty(all))
throw new NoSuchFieldException("no such field for class " + memberClz.getName());
return all.toArray(new Field[0]);
}
public static Field fieldByNameRecursive(Class clz, String fieldName) throws NoSuchFieldException {
Class target = clz;
while (!target.equals(Object.class)) {
try {
Field field = target.getDeclaredField(fieldName);
return field;
} catch (NoSuchFieldException e) {
target = clz.getSuperclass();
}
}
throw new NoSuchFieldException(fieldName);
}
// public static void printAllFields(Class clz) {
//
// Class target = clz;
// String prefix = "===";
// int depth = 1;
// String p = null;
// while (!target.equals(Object.class)) {
// Field[] fields = target.getDeclaredFields();
// p = StringUtils.repeat(prefix, depth);
// NLog.i(TAG, "%s%s Fields:", p, target.getName());
// if (fields != null && fields.length > 0) {
// for(int i= 0; i< fields.length; i++) {
// NLog.i(TAG,"%s Field[%d]: %s%s %s", p, i,
// modifiers(fields[i].getModifiers()),
// className(fields[i].getType()),
// fields[i].getName()
// );
// }
// }
// }
// }
private static String className(Class clz) {
if (clz.isPrimitive()) {
Class s = wrappedClass(clz);
return s != null? s.getName(): null;
} else {
return clz.getName();
}
}
private static String modifiers(int modifiers) {
StringBuilder sb = new StringBuilder();
if (Modifier.isPublic(modifiers)) {
sb.append("public ");
}
else if (Modifier.isPrivate(modifiers)) {
sb.append("private ");
}
else if (Modifier.isProtected(modifiers)) {
sb.append("protected ");
}
if (Modifier.isFinal(modifiers)) {
sb.append("final ");
}
if (Modifier.isStatic(modifiers)) {
sb.append("static ");
}
if (Modifier.isVolatile(modifiers)) {
sb.append("volatile ");
}
return sb.toString();
}
/* public static void test(String a) {
System.out.println("test " + a);
}*/
public static void main(String[] args) {
String test = "okabc";
try {
Object value = 1f;
System.out.println(String.class.isInstance(value));
Object o = InvokeUtil.invokeMethod(test, "equals", 1);
System.out.println(o);
InvokeUtil.invokeStaticMethod(InvokeUtil.class, "test", new Object[]{null});
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
Android P(9.0)反射限制:
上述反射的方式在android P上被限制(android 9.0禁止通过放射调用系统的的非公开方法),此路不同(If they cut off one head, two more shall take it's place... Hail Hydra.),还有千万条路
GitHub:https://github.com/LovelyLittleDemon/ShareMemoryRemote
binder 限制(binder的android上的限制1M,而且是被多个进程共享的);
binder 在android进程中经过一次内存copy,内存共享通过mmap,0次copy效率更高;