Day13-进程间通信

2017-09-05  本文已影响32人  我不是死胖子

进程

进程有自己的内存地址, 一个进程中的1000地址可能在另一个进程中是10000, java的引用本质上还是内存地址, 如果要传递一个类的实例, 还需要传递方法等等, 方法是独立与类对象存在的, 所以到另一个进程中去引用同一个方法就错了, 还是因为独立内存地址的原因.
Android中Activity之间并不能保证两个Activity在同一个进程中, 比如一个APP调用系统打电话功能, 就是两个进程, 所以需要进程间通信

序列化

和JSON XML不同的是 JSON XML 是字符描述型对象, 它们是通用的, 不依赖于任何语言平台

SerializableLink

JVM 虚拟机中的对象, 其内部的状态只存在于内存中, JVM 停止后这些数据就丢失了, 所以考虑到持久化 , 通常是保存在文件系统或者数据库中, 比如 对象映射关系(Object-relational mapping), 对象序列化机制(Object serialization)是Java提供的一种对象持久化方式, 将JVM中的对象和字节数组流之间进行转换

过程简述: Java 的 ObjectOutputStream 类用来持久化一个对象, 通过 writeObject 方法把这个类的对象写到一个文件, 再通过 ObjectInputStream 的readObject 方法把这个对象读出来.

过程
查看 serialVersionUID 的方法
  1. .dat方法查询 Link 不推荐
  2. serialver 命令 Link
    cd 到 java 文件目录, java文件直接 javac 类名.class编译, 并 serialver 类名, android 需要将文件删掉包名, 并没有父类或父类也跟着复制过来

Parcelable

Parcel

是一系列java通过C++调用内存的操作, 将序列化的数据写入共享内存, 实现跨进程通信

  1. 根据这句宏定义得出,Link
#define PAD_SIZE(s) (((s)+3)&~3

内存存放机制和C++的结构体的内存对齐一样, 即读取最小字节位32bit(4字节), 如果高于4字节, 以实际数据类型存放, 但得为4的倍数

由此可以知道, 当我们写入/读取一个数据时, 偏移量至少为4Byte, 偏移量公式
f(x) = 4 * x (x=0, 1, ...)

  1. writeXXX 和 readXXX 导致的偏移量是共用的, 我们在writeInt(23)后, 此时的dataposition = 4, 读取的时候, 我们需要将偏移量置为0, 再从0开始读取4个字节, 所以需要先 setDataPosition(0), 再readInt().
  2. 如果预分配的空间不够时newSize = ((mDataSize+len) * 3)/2;会一次多分配50%;
  3. 对于不同数据的存储不一样
    • 对于普通数据, 使用的是 mData 内存地址,
    • 对于IBinder 或者 FileDescriptor, 使用的是 mObjects 内存地址, 通过 flatten_binder() 和 unflatten_binder()实现, 目的是反序列化时读出的对象就是愿对象而不是 new 出来的新对象

    测试BinderData 但是目前已经不能找不到 BinderData 这个类

有两个成员
uint8_t* mData; //用来存储序列化流数据,可以把它理解成共享内存
size_t* mObjects;  //用来存储IBinder和FileDescriptor

引用和IBinder的序列化方式不一样

过程

Serializable 完整传递过程

结论: Intent 传递的 Serializable 数据最后还是由 Parcel 传递给 C++ 操作, 但是 比普通的 Parcel 数据多了调用 Stream 的 I/O 操作
传递是靠这两句

intent.putExtra("myserializabledata", persion);
startActivity(intent);

先看第一句

  1. Intent.putExtra
public Intent putExtra(String name, Serializable value) {
        if (mExtras == null) {
            mExtras = new Bundle();
        }
        //调用了 Bundle.putSerializable
        mExtras.putSerializable(name, value);
        return this;
    }
  1. -> Bundle.putSerializable
@Override
public void putSerializable(@Nullable String key, @Nullable Serializable value) {
    //调用了BaseBundle.putSerializable
    super.putSerializable(key, value);
}
  1. -> BaseBundle.putSerializable
void putSerializable(@Nullable String key, @Nullable Serializable value) {
    unparcel();
    //数据存在 BaseBundle.mMap
    mMap.put(key, value);
}

最后将 Serializable 存在了 BaseBundle 的 mMap.

再看第二句

  1. startActivity 可以理解为最后由 ActivityManager 执行, 而ActivityManager在源码中各版本不一定一致, 先看4.4.4的
public int startActivity(IApplicationThread caller, String callingPackage, Intent intent,
            String resolvedType, IBinder resultTo, String resultWho, int requestCode,
            int startFlags, String profileFile,
            ParcelFileDescriptor profileFd, Bundle options) throws RemoteException {
        Parcel data = Parcel.obtain();
        Parcel reply = Parcel.obtain();
        data.writeInterfaceToken(IActivityManager.descriptor);

        ...

        if (options != null) {
            data.writeInt(1);
            //这里调用 Bundle.writeToParcel
            options.writeToParcel(data, 0);
        } else {
            data.writeInt(0);
        }

        ...

        return result;
    }
  1. -> Bundle.writeToParcel
@Override
 public void writeToParcel(Parcel parcel, int flags) {
     final boolean oldAllowFds = parcel.pushAllowFds((mFlags & FLAG_ALLOW_FDS) != 0);
     try {
       //调用 BaseBundle.writeToParcelInner
         super.writeToParcelInner(parcel, flags);
     } finally {
         parcel.restoreAllowFds(oldAllowFds);
     }
 }
  1. -> BaseBundle.writeToParcelInner(parcel, flags)
void writeToParcelInner(Parcel parcel, int flags) {
        // Keep implementation in sync with writeToParcel() in
        // frameworks/native/libs/binder/PersistableBundle.cpp.
        final Parcel parcelledData;
        synchronized (this) {
            parcelledData = mParcelledData;
        }
        if (parcelledData != null) {
            if (isEmptyParcel()) {
                parcel.writeInt(0);
            } else {
                int length = parcelledData.dataSize();
                parcel.writeInt(length);
                parcel.writeInt(BUNDLE_MAGIC);
                parcel.appendFrom(parcelledData, 0, length);
            }
        } else {
            // Special case for empty bundles.
            if (mMap == null || mMap.size() <= 0) {
                parcel.writeInt(0);
                return;
            }
            int lengthPos = parcel.dataPosition();
            parcel.writeInt(-1); // dummy, will hold length
            parcel.writeInt(BUNDLE_MAGIC);

            int startPos = parcel.dataPosition();
            // 调用 Parcel.writeArrayMapInternal
            parcel.writeArrayMapInternal(mMap);
            int endPos = parcel.dataPosition();

            // Backpatch length
            parcel.setDataPosition(lengthPos);
            int length = endPos - startPos;
            parcel.writeInt(length);
            parcel.setDataPosition(endPos);
        }
    }
  1. -> Parcel.writeArrayMapInternal(mMap)
void writeArrayMapInternal(ArrayMap<String, Object> val) {
    if (val == null) {
        writeInt(-1);
        return;
    }
    // Keep the format of this Parcel in sync with writeToParcelInner() in
    // frameworks/native/libs/binder/PersistableBundle.cpp.
    final int N = val.size();
    writeInt(N);
    if (DEBUG_ARRAY_MAP) {
        RuntimeException here =  new RuntimeException("here");
        here.fillInStackTrace();
        Log.d(TAG, "Writing " + N + " ArrayMap entries", here);
    }
    int startPos;
    for (int i=0; i<N; i++) {
        if (DEBUG_ARRAY_MAP) startPos = dataPosition();
        writeString(val.keyAt(i));
        //开始操作 map 中的 value
        writeValue(val.valueAt(i));
        if (DEBUG_ARRAY_MAP) Log.d(TAG, "  Write #" + i + " "
                + (dataPosition()-startPos) + " bytes: key=0x"
                + Integer.toHexString(val.keyAt(i) != null ? val.keyAt(i).hashCode() : 0)
                + " " + val.keyAt(i));
    }
}

这里操作了第一步生成的 mMAp

  1. -> parcel.writeValue
public final void writeValue(Object v) {
       if (v == null) {
           writeInt(VAL_NULL);
       } else if (v instanceof String) {
           writeInt(VAL_STRING);
           writeString((String) v);
       } else if (v instanceof Integer) {
           writeInt(VAL_INTEGER);
           writeInt((Integer) v);
       } else if (v instanceof Map) {
           writeInt(VAL_MAP);
           writeMap((Map) v);
       } else if (v instanceof Bundle) {
           // Must be before Parcelable
           writeInt(VAL_BUNDLE);
           writeBundle((Bundle) v);
       } else if (v instanceof PersistableBundle) {
           writeInt(VAL_PERSISTABLEBUNDLE);
           writePersistableBundle((PersistableBundle) v);
       } else if (v instanceof Parcelable) {
           // IMPOTANT: cases for classes that implement Parcelable must
           // come before the Parcelable case, so that their specific VAL_*
           // types will be written.
           writeInt(VAL_PARCELABLE);
           writeParcelable((Parcelable) v, 0);
       } else {
           Class<?> clazz = v.getClass();
           if (clazz.isArray() && clazz.getComponentType() == Object.class) {
               // Only pure Object[] are written here, Other arrays of non-primitive types are
               // handled by serialization as this does not record the component type.
               writeInt(VAL_OBJECTARRAY);
               writeArray((Object[]) v);
           } else if (v instanceof Serializable) {
               // Must be last
               writeInt(VAL_SERIALIZABLE);
               //对 Serializable 操作
               writeSerializable((Serializable) v);
           } else {
               throw new RuntimeException("Parcel: unable to marshal value " + v);
           }
       }
   }  

在writeValue的最后,处理了 Serializable

  1. -> Parcel.writeSerializable()
public final void writeSerializable(Serializable s) {
        if (s == null) {
            writeString(null);
            return;
        }
        String name = s.getClass().getName();
        writeString(name);

        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        try {
            ObjectOutputStream oos = new ObjectOutputStream(baos);
            oos.writeObject(s);
            oos.close();
            //将Serializable I/O操作后转换成字节流
            writeByteArray(baos.toByteArray());
        } catch (IOException ioe) {
            throw new RuntimeException("Parcelable encountered " +
                "IOException writing serializable object (name = " + name +
                ")", ioe);
        }
    }
  1. -> Parcel.writeByteArray()
public final void writeByteArray(byte[] b) {
     //对流判断
     writeByteArray(b, 0, (b != null) ? b.length : 0);
 }
  1. -> Parcel.nativeWriteByteArray()
public final void writeByteArray(byte[] b, int offset, int len) {
   if (b == null) {
       writeInt(-1);
       return;
   }
   Arrays.checkOffsetAndCount(b.length, offset, len);
   //调用了 native 方法
   nativeWriteByteArray(mNativePtr, b, offset, len);
}

Intent

Intent 的 bundle 使用Binder机制进行数据传递, 能使用Binder的缓冲区有大小限制, 有些手机是2M
一个进程默认有16个 Binder线程, 所以一个线程所能占用的缓冲区更小了(大约一个线程128KB), 所以当出现The Binder transaction failed because it was too large, 说明数据太大.
因此Intent传递List和Bitmap对象是存在风险的

参考

上一篇 下一篇

猜你喜欢

热点阅读