Unzip.java
package com.android.xxx;
import android.util.Log;
class Unzip{
private static final String TAG = "Unzip";
public static boolean unzipSOFile() {
Log.d("ZLoader", "Unzip::unzipSOFile");
return nativeUnzipSOFile();
}
public static void loadLibCompleted() {
Log.d("ZLoader", "Unzip::loadLibCompleted");
nativeLoadLibCompleted();
}
private static native boolean nativeUnzipSOFile();
private static native void nativeLoadLibCompleted();
}
c++文件, 使用mmm生成so文件
Unzip.cpp
#define LOG_TAG "Unzip"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include "zlib.h"
#include <jni.h>
#include <string.h>
#include "base/logging.h"
#include <android/log.h>
namespace android {
namespace {
#define BUFFER_SIZE 16384
#define NELEM(x) ((int) (sizeof(x) / sizeof((x)[0])))
#define COMPILE_ASSERT(expr, err) static const char err[(expr) ? 1 : -1] = "";
bool Compress(const char * DestName,const char *SrcName)
{
if (!DestName || !SrcName) {
__android_log_print(ANDROID_LOG_DEBUG, "Tag", "Parameters error: DestName=%p, SrcName=%p\n", DestName, SrcName);
return false;
}
FILE * fp_in = NULL;
int len = 0;
char buf[BUFFER_SIZE];
if (NULL == (fp_in = fopen(SrcName,"rb"))) {
__android_log_print(ANDROID_LOG_DEBUG, "Tag", "Can not open file: %s", SrcName);
return false;
}
/
gzFile out = gzopen(DestName,"wb6f");
if (out == NULL) {
__android_log_print(ANDROID_LOG_DEBUG, "Tag", "Can not open file: %s", DestName);
return false;
}
bool re = true;
for (;;) {
len = fread(buf,1,sizeof(buf),fp_in);
if (ferror(fp_in)) {
re = false;
break;
}
if (len == 0) break;
if(gzwrite(out, buf, (unsigned)len) != len) {
re = false;
}
}
gzclose(out);
fclose(fp_in);
return re;
}
bool UnCompress(const char * DestName,const char *SrcName)
{
if (!DestName || !SrcName) {
__android_log_print(ANDROID_LOG_DEBUG, "Tag", "Parameters error: DestName=%p, SrcName=%p\n", DestName, SrcName);
return false;
}
FILE * fp_out = NULL;
bool re = true;
gzFile in;
unsigned int len = 0;
char buf[BUFFER_SIZE];
in = gzopen(SrcName,"rb");
if (in == NULL) {
__android_log_print(ANDROID_LOG_DEBUG, "Tag", "Open Src file error: %s", SrcName);
return false;
}
if (NULL == (fp_out = fopen(DestName,"wb"))) {
gzclose(in);
__android_log_print(ANDROID_LOG_DEBUG, "Tag", "Open Dest file error: %s(%s)", DestName, strerror(errno));
return false;
}
for (;;) {
len = gzread(in,buf,sizeof(buf));
if(len < 0) {
re = false;
break;
}
if(len == 0) break;
if(fwrite(buf,1,(unsigned)len,fp_out) != len) {
re = false;
break;
}
}
fclose(fp_out);
gzclose(in);
return re;
}
#ifdef UNZIP_TEST
int main(void)
{
bool re = Compress("./a.so", "./b.so");
if (!re) {
printf("Compress error!\n");
} else {
printf("Compress success!\n");
}
re = UnCompress("./b.so", "./a.so");
if (!re) {
printf("Uncompress error!\n");
} else {
printf("Uncompress success!\n");
}
return 0;
}
#endif
const char originLibName[] = "/data/data/com.android.xxx/lib/liba.so";
const char dstLibName[] = "/data/data/com.android.xxx/lib/libb.so";
jboolean UnzipSOFile(JNIEnv*) {
__android_log_print(ANDROID_LOG_DEBUG, "Tag", "UnzipSOfile!\n");
bool re = UnCompress(dstLibName, originLibName);
if (!re) {
__android_log_print(ANDROID_LOG_DEBUG, "Tag", "Unzip dynamic library error.");
}
return static_cast<jboolean>(re);
}
void LoadLibCompleted(JNIEnv*) {
remove(dstLibName);
}
const char kClassName[] = "com/android/xxx/Unzip";
const JNINativeMethod kJniMethods[] = {
{ "nativeUnzipSOFile", "()Z",
reinterpret_cast<void*>(UnzipSOFile) },
{ "nativeLoadLibCompleted", "()V",
reinterpret_cast<void*>(LoadLibCompleted) }
};
} // namespace
void RegisterZLoader(JNIEnv* env) {
jclass clazz = env->FindClass(kClassName);
int res = env->RegisterNatives(clazz, kJniMethods, NELEM(kJniMethods));
}
} // namespace android
jni_entry_point.cpp
#include <jni.h>
#include <stdio.h>
#include <android/log.h>
namespace android {
void RegisterZLoader(JNIEnv* env);
} // namespace android
JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved) {
__android_log_print(ANDROID_LOG_DEBUG, "Tag", "Unzip -> JNI_OnLoad\n");
JNIEnv* env = 0;
jint ret = vm->AttachCurrentThread(&env, 0);
android::RegisterZLoader(env);
return JNI_VERSION_1_4;
}
Android.mk
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
TARGET_BUILD_APPS := false
LOCAL_ARM_MODE := arm
LOCAL_MODULE := libUnzip
LOCAL_MODULE_TAGS := optional
LOCAL_SRC_FILES:= \
jni_entry_point.cpp \
Unzip.cpp
LOCAL_C_INCLUDES:= \
$(SYSROOT_INC)/usr/include \
$(PWD)/ndk/sources/cxx-stl/stlport/stlport \
$(PWD)/external/chromium_org \
$(PWD)/external/chromium_org/third_party/zlib
LOCAL_C_INCLUDES_Release := \
$(LOCAL_C_INCLUDES)
LOCAL_C_INCLUDES_Debug := \
$(LOCAL_C_INCLUDES)
LOCAL_CFLAGS += -DAVOID_TABLES
LOCAL_CPPFLAGS_Release := \
-fPIC \
MY_CFLAGS_Release := \
-fPIC \
LOCAL_LDFLAGS_Release := \
-fPIC \
LOCAL_SHARED_LIBRARIES := libz liblog
LOCAL_CFLAGS := $(MY_CFLAGS_$(GYP_CONFIGURATION)) $(MY_DEFS_$(GYP_CONFIGURATION))
LOCAL_CPPFLAGS := $(LOCAL_CPPFLAGS_$(GYP_CONFIGURATION))
LOCAL_LDFLAGS := $(LOCAL_LDFLAGS_$(GYP_CONFIGURATION))
include $(BUILD_SHARED_LIBRARY)
注:
1.Android JNI 使用的数据结构JNINativeMethod
typedef struct {
const char* name; // Java中函数的名字
const char* signature; // 描述了函数的参数和返回值的字符串
void* fnPtr; // C函数指针
} JNINativeMethod;
http://hi.baidu.com/leicejbgnndjrze/item/b87a4895e06a6c1c924f41f4
第二个参数
"()" 中的字符表示参数,后面的则代表返回值。例如"()V" 就表示void Func();
"(II)V" 表示 void Func(int, int);
在编译chromium(android4.4)时产生好多jni目录,里面有很多这样的例子
out/target/product/generic/obj/GYP/shared_intermediates/android_view/jni/
具体的每一个字符的对应关系如下
字符 Java类型 C类型
V void void
Z jboolean boolean
I jint int
J jlong long
D jdouble double
F jfloat float
B jbyte byte
C jchar char
S jshort short
数组则以"["开始,用两个字符表示
[I jintArray int[]
[F jfloatArray float[]
[B jbyteArray byte[]
[C jcharArray char[]
[S jshortArray short[]
[D jdoubleArray double[]
[J jlongArray long[]
[Z jbooleanArray boolean[]
上面的都是基本类型。如果Java函数的参数是class,则以"L"开头,以";"结尾中间是用"/" 隔开的包及类名。而其对应的C函数名的参数则为jobject. 一个例外是String类,其对应的类为jstring
Ljava/lang/String; String jstring
Ljava/net/Socket; Socket jobject
如果JAVA函数位于一个嵌入类,则用$作为类名间的分隔符。
例如 "(Ljava/lang/String;Landroid/os/FileUtils$FileStatus;)Z"
2. native log re-direct logcat
使用android/log.h, 提供了4个函数
int __android_log_write(int prio, const char *tag, const char *text);
int __android_log_print(int prio, const char *tag, const char *fmt, ...) ;
int __android_log_vprint(int prio, const char *tag, const char *fmt, va_list ap);
void __android_log_assert(const char *cond, const char *tag, const char *fmt, ...) ;
其中参数prio的值有:
typedef enum android_LogPriority {
ANDROID_LOG_UNKNOWN = 0,
ANDROID_LOG_DEFAULT, /* only for SetMinPriority() */
ANDROID_LOG_VERBOSE,
ANDROID_LOG_DEBUG,
ANDROID_LOG_INFO,
ANDROID_LOG_WARN,
ANDROID_LOG_ERROR,
ANDROID_LOG_FATAL,
ANDROID_LOG_SILENT, /* only for SetMinPriority(); must be last */
} android_LogPriority;