Android Ashmem匿名共享内存 Java实例

packages/experimental/


知识点:


1、需要用反射来获取 MemoryFile.getFileDescriptor方法以及设置private成员变量;

2、AIDL的使用。


Ashmem/aidl/com/mycompany/ashmem/IMemoryService.aidl

// IMemoryService.aidl
package com.mycompany.ashmem;

import android.os.ParcelFileDescriptor;

// Declare any non-default types here with import statements

interface IMemoryService {
    /**
     * Demonstrates some basic types that you can use as parameters
     * and return values in AIDL.
     */
    void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat,
            double aDouble, String aString);

    ParcelFileDescriptor getFileDescriptor();
    void setValue(int val);
}


由Ashmem/aidl/com/mycompany/ashmem/IMemoryService.aidl编译出来的 IMemoryService.java文件

/*
 * This file is auto-generated.  DO NOT MODIFY.
 * Original file: packages/experimental/Ashmem/aidl/com/mycompany/ashmem/IMemoryService.aidl
 */
package com.mycompany.ashmem;
// Declare any non-default types here with import statements

public interface IMemoryService extends android.os.IInterface {
    /**
     * Local-side IPC implementation stub class.
     */
    public static abstract class Stub extends android.os.Binder implements com.mycompany.ashmem.IMemoryService {
        private static final java.lang.String DESCRIPTOR = "com.mycompany.ashmem.IMemoryService";

        /**
         * Construct the stub at attach it to the interface.
         */
        public Stub() {
            this.attachInterface(this, DESCRIPTOR);
        }

        /**
         * Cast an IBinder object into an com.mycompany.ashmem.IMemoryService interface,
         * generating a proxy if needed.
         */
        public static com.mycompany.ashmem.IMemoryService asInterface(android.os.IBinder obj) {
            if ((obj == null)) {
                return null;
            }
            android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
            if (((iin != null) && (iin instanceof com.mycompany.ashmem.IMemoryService))) {
                return ((com.mycompany.ashmem.IMemoryService) iin);
            }
            return new com.mycompany.ashmem.IMemoryService.Stub.Proxy(obj);
        }

        @Override
        public android.os.IBinder asBinder() {
            return this;
        }

        @Override
        public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException {
            switch (code) {
                case INTERFACE_TRANSACTION: {
                    reply.writeString(DESCRIPTOR);
                    return true;
                }
                case TRANSACTION_basicTypes: {
                    data.enforceInterface(DESCRIPTOR);
                    int _arg0;
                    _arg0 = data.readInt();
                    long _arg1;
                    _arg1 = data.readLong();
                    boolean _arg2;
                    _arg2 = (0 != data.readInt());
                    float _arg3;
                    _arg3 = data.readFloat();
                    double _arg4;
                    _arg4 = data.readDouble();
                    java.lang.String _arg5;
                    _arg5 = data.readString();
                    this.basicTypes(_arg0, _arg1, _arg2, _arg3, _arg4, _arg5);
                    reply.writeNoException();
                    return true;
                }
                case TRANSACTION_getFileDescriptor: {
                    data.enforceInterface(DESCRIPTOR);
                    android.os.ParcelFileDescriptor _result = this.getFileDescriptor();
                    reply.writeNoException();
                    if ((_result != null)) {
                        reply.writeInt(1);
                        _result.writeToParcel(reply, android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
                    } else {
                        reply.writeInt(0);
                    }
                    return true;
                }
                case TRANSACTION_setValue: {
                    data.enforceInterface(DESCRIPTOR);
                    int _arg0;
                    _arg0 = data.readInt();
                    this.setValue(_arg0);
                    reply.writeNoException();
                    return true;
                }
            }
            return super.onTransact(code, data, reply, flags);
        }

        private static class Proxy implements com.mycompany.ashmem.IMemoryService {
            private android.os.IBinder mRemote;

            Proxy(android.os.IBinder remote) {
                mRemote = remote;
            }

            @Override
            public android.os.IBinder asBinder() {
                return mRemote;
            }

            public java.lang.String getInterfaceDescriptor() {
                return DESCRIPTOR;
            }

            /**
             * Demonstrates some basic types that you can use as parameters
             * and return values in AIDL.
             */
            @Override
            public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, java.lang.String aString) throws android.os.RemoteException {
                android.os.Parcel _data = android.os.Parcel.obtain();
                android.os.Parcel _reply = android.os.Parcel.obtain();
                try {
                    _data.writeInterfaceToken(DESCRIPTOR);
                    _data.writeInt(anInt);
                    _data.writeLong(aLong);
                    _data.writeInt(((aBoolean) ? (1) : (0)));
                    _data.writeFloat(aFloat);
                    _data.writeDouble(aDouble);
                    _data.writeString(aString);
                    mRemote.transact(Stub.TRANSACTION_basicTypes, _data, _reply, 0);
                    _reply.readException();
                } finally {
                    _reply.recycle();
                    _data.recycle();
                }
            }

            @Override
            public android.os.ParcelFileDescriptor getFileDescriptor() throws android.os.RemoteException {
                android.os.Parcel _data = android.os.Parcel.obtain();
                android.os.Parcel _reply = android.os.Parcel.obtain();
                android.os.ParcelFileDescriptor _result;
                try {
                    _data.writeInterfaceToken(DESCRIPTOR);
                    mRemote.transact(Stub.TRANSACTION_getFileDescriptor, _data, _reply, 0);
                    _reply.readException();
                    if ((0 != _reply.readInt())) {
                        _result = android.os.ParcelFileDescriptor.CREATOR.createFromParcel(_reply);
                    } else {
                        _result = null;
                    }
                } finally {
                    _reply.recycle();
                    _data.recycle();
                }
                return _result;
            }

            @Override
            public void setValue(int val) throws android.os.RemoteException {
                android.os.Parcel _data = android.os.Parcel.obtain();
                android.os.Parcel _reply = android.os.Parcel.obtain();
                try {
                    _data.writeInterfaceToken(DESCRIPTOR);
                    _data.writeInt(val);
                    mRemote.transact(Stub.TRANSACTION_setValue, _data, _reply, 0);
                    _reply.readException();
                } finally {
                    _reply.recycle();
                    _data.recycle();
                }
            }
        }

        static final int TRANSACTION_basicTypes = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
        static final int TRANSACTION_getFileDescriptor = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
        static final int TRANSACTION_setValue = (android.os.IBinder.FIRST_CALL_TRANSACTION + 2);
    }

    /**
     * Demonstrates some basic types that you can use as parameters
     * and return values in AIDL.
     */
    public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, java.lang.String aString) throws android.os.RemoteException;

    public android.os.ParcelFileDescriptor getFileDescriptor() throws android.os.RemoteException;

    public void setValue(int val) throws android.os.RemoteException;
}


Ashmem/AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.mycompany.ashmem"
    android:sharedUserId="android.uid.system">

    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:supportsRtl="true">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <service android:name="com.mycompany.ashmem.Server">
            <intent-filter>
                <action android:name="com.mycompany.ashmem.Server"></action>
            </intent-filter>
        </service>
    </application>

</manifest>

Ashmem/Android.mk

# Copyright (C) 2010 Google Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#

LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)

LOCAL_MODULE_TAGS := optional

LOCAL_SRC_FILES := $(call all-java-files-under, src)

LOCAL_SRC_FILES += aidl/com/mycompany/ashmem/IMemoryService.aidl

LOCAL_PACKAGE_NAME := Ashmem
LOCAL_CERTIFICATE := platform

include $(BUILD_PACKAGE)


Ashmem/res/layout/activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context="com.mycompany.ashmem.MainActivity">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/value" />

    <EditText
        android:id="@+id/editText"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:ems="10"
        android:inputType="number"
        android:hint="@string/hint"/>

    <Button
        android:id="@+id/button_read"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/read"
        tools:layout_editor_absoluteX="48dp"
        tools:layout_editor_absoluteY="209dp" />

    <Button
        android:id="@+id/button_write"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/write"
        tools:layout_editor_absoluteX="48dp"
        tools:layout_editor_absoluteY="274dp" />

    <Button
        android:id="@+id/button_clear"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/clear"
        tools:layout_editor_absoluteX="48dp"
        tools:layout_editor_absoluteY="333dp" />

</LinearLayout>


Ashmem/res/values/strings.xml

<resources>
    <string name="app_name">Ashmem</string>
    <string name="value" />
    <string name="hint">Please input a value...</string>
    <string name="read">Read</string>
    <string name="write">write</string>
    <string name="clear">clear</string>
</resources>


Ashmem

└── src
    └── com
        └── mycompany
            └── ashmem
                ├── MainActivity.java

package com.mycompany.ashmem;

import android.app.Activity;
import android.content.Intent;
import android.content.ComponentName;
import android.os.MemoryFile;
import android.os.ParcelFileDescriptor;
import android.os.RemoteException;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;

import java.io.FileDescriptor;
import java.io.IOException;
import java.io.*;
import java.lang.reflect.*;

import android.os.ServiceManager;

public class MainActivity extends Activity implements View.OnClickListener {
    private final static String TAG = "MainActivity";

    IMemoryService memoryService = null;
    MemoryFile memoryFile = null;
    FileInputStream inputStream = null;
    private EditText valueText = null;
    private Button readButton = null;
    private Button writeButton = null;
    private Button clearButton = null;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        IMemoryService ms = getMemoryService();
        if (ms == null) {
            Log.i(TAG, "start server");
            Intent intents = new Intent();
            intents.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            intents.setClassName("com.mycompany.ashmem", "com.mycompany.ashmem.Server");
            startService(intents);
        } else {
            Log.i(TAG, "Memory Service has started.");
        }

        valueText = (EditText) findViewById(R.id.editText);
        readButton = (Button) findViewById(R.id.button_read);
        writeButton = (Button) findViewById(R.id.button_write);
        clearButton = (Button) findViewById(R.id.button_clear);
        readButton.setOnClickListener(this);
        writeButton.setOnClickListener(this);
        clearButton.setOnClickListener(this);

        Log.i(TAG, "client activity cretaed.");
    }

    @Override
    public void onClick(View v) {
        int val = 0;
        String text = "";

        switch (v.getId()) {
            case R.id.button_read:
                Log.i(TAG, "button read.");
                val = 0;
                MemoryFile mf = getMemoryFile();

                if (mf != null) {
                    try {
                        byte[] buffer = new byte[4];
                        mf.readBytes(buffer, 0, 0, 4);
                        val = (buffer[0] << 24) | ((buffer[1] & 0xFF) << 16) |
                                ((buffer[2] & 0xFF) << 8) | (buffer[3] & 0xFF);
                        Log.i(TAG, "read file " + val);
                    } catch (IOException e) {
                        Log.i(TAG, "Failed to read bytes from memory file.");
                        e.printStackTrace();
                    }
                } else {
                    Log.e(TAG, "MemoryFile is null");
                }

                text = String.valueOf(val);
                valueText.setText(text);
                valueText.setSelection(valueText.getText().length());
                break;
            case R.id.button_write:
                Log.i(TAG, "button write.");
                text = valueText.getText().toString();

                if (text.equals("")) {
                    Toast.makeText(this, "Please input a number!", Toast.LENGTH_SHORT).show();
                    break;
                }
                try {
                    val = Integer.parseInt(text);
                } catch (NumberFormatException e) {
                    Toast.makeText(this, e.getMessage(), Toast.LENGTH_SHORT).show();
                    break;
                }

                IMemoryService ms = getMemoryService();
                if (ms != null) {
                    try {
                        ms.setValue(val);
                    } catch (RemoteException e) {
                        Log.e(TAG, "Failed to set value to memory service.");
                        e.printStackTrace();
                    }
                } else {
                    Log.e(TAG, "Memory Service is null");
                }

                break;
            case R.id.button_clear:
                text = "";
                valueText.setText(text);
                break;
        }
    }

    private IMemoryService getMemoryService() {
        if (memoryService != null) {
            Log.i(TAG, "memory service aleady started.");
            return memoryService;
        }

        memoryService = IMemoryService.Stub.asInterface(ServiceManager.getService("AnonymousSharedMemory"));
        Log.i(TAG, memoryService != null ? "Succeed to get memory service." : "Failed to get memory service.");
        return memoryService;
    }


    /**
     *
     */
    public void setField(String className, Object instance, String fieldName, Object value) {
        if (className == null || className.equals("")) {
            throw new IllegalArgumentException("className is null");
        }
        if (fieldName == null || fieldName.equals("")) {
            throw new IllegalArgumentException("fieldName is null");
        }
        try {
            Class<?> c = Class.forName(className);
            Field field = c.getDeclaredField(fieldName);
            field.setAccessible(true);
            field.set(instance, value);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private MemoryFile getMemoryFile() {
        if (memoryFile != null) {
            return memoryFile;
        }

        IMemoryService ms = getMemoryService();
        if (ms != null) {
            try {
                ParcelFileDescriptor pfd = ms.getFileDescriptor();
                if (pfd == null) {
                    Log.i(TAG, "Failed to get memory file descriptor.");
                    return null;
                }
                FileDescriptor fd = pfd.getFileDescriptor();
                if (fd == null) {
                    Log.e(TAG, "Failed to get memory file descriptor.");
                    return null;
                }

                int length = 4;
                memoryFile = new MemoryFile("r", length);
                memoryFile.close();

                try {
                    Method native_mmap = null;
                    Method[] methods = MemoryFile.class.getDeclaredMethods();
                    for (int i = 0; methods != null && i < methods.length; i++) {
                        if (methods[i].getName().equals("native_mmap")) {
                            Log.i(TAG, "native_mmap finded.");
                            native_mmap = methods[i];
                            setField("android.os.MemoryFile", memoryFile, "mFD", fd);
                            setField("android.os.MemoryFile", memoryFile, "mLength", length);
                            native_mmap.setAccessible(true);
                            long address = (long) native_mmap.invoke(null, fd, length, 0x01 | 0x02);
                            setField("android.os.MemoryFile", memoryFile, "mAddress", address);
                        }
                    }
                } catch (IllegalAccessException e) {
                    Log.e(TAG, "IllegalAccessException:" + e.getMessage());
                    e.printStackTrace();
                } catch (InvocationTargetException e) {
                    Log.e(TAG, "InvocationTargetException:" + e.getMessage());
                    e.printStackTrace();
                }

                return memoryFile;
            } catch (RemoteException e) {
                Log.e(TAG, "Failed to get file descriptor from memory service.");
                e.printStackTrace();
            } catch (IOException e) {
                Log.e(TAG, "Failed to create memory file.");
                e.printStackTrace();
            }
        } else {
            Log.e(TAG, "memory service is null");
        }

        return memoryFile;
    }
}

Ashmem
└── src
    └── com
        └── mycompany
            └── ashmem
                ├── MemoryService.java

package com.mycompany.ashmem;

import android.os.MemoryFile;
import android.os.ParcelFileDescriptor;
import android.os.RemoteException;
import android.util.Log;

import java.io.IOException;
import java.io.*;
import java.lang.reflect.*;

/**
 * Created by Administrator on 2017/4/1.
 */

public class MemoryService extends IMemoryService.Stub {
    private final static String TAG = "MemoryService";
    private MemoryFile file = null;

    public MemoryService() {
        Log.i(TAG, "MemoryService");
        try {
            file = new MemoryFile("Ashmem", 4);
            setValue(0);
        } catch (IOException e) {
            Log.i(TAG, "Failed to create memory file.");
            e.printStackTrace();
        } catch (RemoteException e) {
            Log.i(TAG, "Failed to setValue().");
            e.printStackTrace();
        }
    }

    @Override
    public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString) throws RemoteException {

    }

    @Override
    public ParcelFileDescriptor getFileDescriptor() throws RemoteException {
        ParcelFileDescriptor pfd = null;

        try {
            Method method = MemoryFile.class.getDeclaredMethod("getFileDescriptor");
            FileDescriptor fd = (FileDescriptor) method.invoke(file);
            pfd = ParcelFileDescriptor.dup(fd);
//            FileDescriptor fd = file.getFileDescriptor();
//            pfd = ParcelFileDescriptor.dup(fd);
            Log.i(TAG, "getFileDescriptor:" + pfd);
        } catch (IOException e) {
            Log.e(TAG, "IOException:" + e.getMessage());
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            Log.e(TAG, "NoSuchMethodException:" + e.getMessage());
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            Log.e(TAG, "IllegalAccessException:" + e.getMessage());
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            Log.e(TAG, "InvocationTargetException:" + e.getMessage());
            e.printStackTrace();
        }
        return pfd;
    }

    @Override
    public void setValue(int val) throws RemoteException {
        if (file == null) {
            Log.e(TAG, "Memory file is null.");
            return;
        }

        Log.i(TAG, "setValue:" + val);

        byte[] buffer = new byte[4];
        buffer[0] = (byte) ((val >>> 24) & 0xFF);
        buffer[1] = (byte) ((val >>> 16) & 0xFF);
        buffer[2] = (byte) ((val >>> 8) & 0xFF);
        buffer[3] = (byte) (val & 0xFF);
        try {
            file.writeBytes(buffer, 0, 0, 4);
            Log.i(TAG, "Set value " + val + " " + buffer[0] + buffer[1] + buffer[2] + buffer[3] + " to memory file.");
        } catch (IOException e) {
            Log.i(TAG, "Failed to write bytes to memory file.");
            e.printStackTrace();
        }
    }
}


Ashmem
└── src
    └── com
        └── mycompany
            └── ashmem
                ├── Server.java

 
 
package com.mycompany.ashmem;

import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.util.Log;
import android.os.ServiceManager;

import java.lang.reflect.Method;

/**
 * Created by Administrator on 2017/4/5.
 */

public class Server extends Service {
    private final static String TAG = "Server";
    private MemoryService memoryService = null;

    @Override
    public IBinder onBind(Intent intent) {
        Log.i(TAG, "onBind");
        return null;
    }

    @Override
    public void onCreate() {
        Log.i(TAG, "onCreate");
        memoryService = new MemoryService();

        try {
            ServiceManager.addService("AnonymousSharedMemory", memoryService);
            Log.i(TAG, "Succeed to add memory service.");
        } catch (RuntimeException e) {
            Log.e(TAG, "Failed to add Memory Service.");
            e.printStackTrace();
        }
    }

    @Override
    public void onStart(Intent intent, int startId) {
        super.onStart(intent, startId);
        Log.i(TAG, "onStart");
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        Log.i(TAG, "onDestroy");
    }
}
 
 
 
 
 
 
 
 
 

猜你喜欢

转载自blog.csdn.net/liudongming_1985/article/details/69948582