【Android】SharedMemory获取文件描述符

SharedMemory用来实现共享内存操作很方便,也提供了获取文件描述符的方法,但是是hide的,普通app不能访问,

java 复制代码
    /**
     * Returns the backing {@link FileDescriptor} for this SharedMemory object. The SharedMemory
     * instance retains ownership of the FileDescriptor.
     *
     * This FileDescriptor is interoperable with the ASharedMemory NDK APIs.
     *
     * @return Returns the FileDescriptor associated with this object.
     *
     * @hide Exists only for MemoryFile interop
     */
    public @NonNull FileDescriptor getFileDescriptor() {
        return mFileDescriptor;
    }

    /**
     * Returns the backing native fd int for this SharedMemory object. The SharedMemory
     * instance retains ownership of the fd.
     *
     * This fd is interoperable with the ASharedMemory NDK APIs.
     *
     * @return Returns the native fd associated with this object, or -1 if it is already closed.
     *
     * @hide Exposed for native ASharedMemory_dupFromJava()
     */
    @UnsupportedAppUsage(trackingBug = 171971817)
    public int getFd() {
        return mFileDescriptor.getInt$();
    }

可以使用反射区获取fd,但是不够优雅,这里看看另外一个方式,通过parcel处理去间接的获取。

java 复制代码
            Parcel pData = Parcel.obtain();

            sharedMemory.writeToParcel(pData, 0);//Parcelable.PARCELABLE_WRITE_RETURN_VALUE

            //here
            pData.setDataPosition(0);
            ParcelFileDescriptor parcelFileDescriptor = pData.readFileDescriptor();

这样就可以获取到文件描述符了,注意,pData.setDataPosition(0);是必须的。

在 Android 中,SharedMemory(共享内存)是一种允许不同进程共享同一块内存区域的机制,常用于高效传输大量数据(如图像、视频等)。以下是其核心要点:


1. 核心概念

  • 作用:避免传统 IPC(如 Binder)的数据拷贝开销,实现跨进程高效数据共享。

  • 底层机制 :基于 Ashmem(Android Shared Memory Driver),一种 Linux 匿名共享内存的优化版本,支持内存区域的动态清理和权限控制。


2. 关键类与 API

  • SharedMemory(API 26+):封装了 Ashmem 的操作,提供创建、映射和管理共享内存的方法。

  • ParcelFileDescriptor:用于跨进程传递共享内存的文件描述符(FD)。

  • MemoryFile(旧版 API 的替代):基于 Ashmem,适用于 API 较低的场景。


3. 使用步骤

创建与映射共享内存

kotlin

复制

复制代码
// 1. 创建 SharedMemory 实例
val sharedMemory = SharedMemory.create("my_shmem", 1024)

// 2. 映射到当前进程内存(可读写)
val buffer = sharedMemory.mapReadWrite()

// 3. 写入数据
buffer.putInt(0, 42) // 示例:在位置 0 写入 Int 值

// 4. 跨进程传递 FD
val pfd = ParcelFileDescriptor.fromFd(sharedMemory.fileDescriptor)
// 通过 Intent/Bundle/AIDL 传递 pfd 给其他进程
其他进程访问共享内存

kotlin

复制

复制代码
// 1. 接收 ParcelFileDescriptor(假设通过 Binder 传递)
val pfd: ParcelFileDescriptor = ...

// 2. 通过 FD 创建 SharedMemory
val sharedMemory = SharedMemory.createFromFd(pfd)

// 3. 映射内存(根据权限选择只读/读写)
val buffer = sharedMemory.mapReadOnly()

// 4. 读取数据
val value = buffer.getInt(0) // 读取位置 0 的 Int 值

// 5. 使用后清理
sharedMemory.unmap(buffer)
sharedMemory.close()

4. 注意事项

  • 同步问题:共享内存无内置同步机制,需自行处理(如使用锁、信号量等)。

  • 内存泄漏 :确保及时调用 unmap()close() 释放资源。

  • 兼容性SharedMemory 需 API 26+,低版本可使用 MemoryFile

  • 权限控制 :通过 setProtect() 设置读写权限(如 Protection.READ)。


5. 使用场景

  • 高性能数据传输:如图像处理、音视频编解码、游戏资源加载。

  • 跨进程大数据共享:替代 Binder 的 1MB 限制,避免序列化开销。


6. 对比其他 IPC

机制 性能 数据大小限制 复杂度
Binder 1MB
文件/ContentProvider
SharedMemory

7. 代码示例(跨进程传递 FD)

发送端
复制代码
val sharedMemory = SharedMemory.create("image_buffer", 1024 * 1024)
val pfd = ParcelFileDescriptor.fromFd(sharedMemory.fileDescriptor)
val intent = Intent().apply { putExtra("shared_fd", pfd) }
startActivity(intent)
接收端
复制代码
val pfd = intent.getParcelableExtra<ParcelFileDescriptor>("shared_fd")
val sharedMemory = SharedMemory.createFromFd(pfd)
val buffer = sharedMemory.mapReadWrite()
// 处理数据...

通过合理使用 SharedMemory,可以显著优化 Android 中跨进程的大数据交互性能,但需注意同步和资源管理。

参考资料:

https://blog.51cto.com/u_16213375/11974814

相关推荐
阿巴斯甜19 小时前
Android 报错:Zip file '/Users/lyy/develop/repoAndroidLapp/l-app-android-ble/app/bu
android
Kapaseker20 小时前
实战 Compose 中的 IntrinsicSize
android·kotlin
xq952721 小时前
Andorid Google 登录接入文档
android
黄林晴1 天前
告别 Modifier 地狱,Compose 样式系统要变天了
android·android jetpack
冬奇Lab1 天前
Android触摸事件分发、手势识别与输入优化实战
android·源码阅读
城东米粉儿2 天前
Android MediaPlayer 笔记
android
Jony_2 天前
Android 启动优化方案
android
阿巴斯甜2 天前
Android studio 报错:Cause: error=86, Bad CPU type in executable
android
张小潇2 天前
AOSP15 Input专题InputReader源码分析
android
_小马快跑_2 天前
Kotlin | 协程调度器选择:何时用CoroutineScope配置,何时用launch指定?
android