system에 library를 embedding하고, 그것을 apk가 사용하고자 할때... (여러 apk에서 공유가능.)


Sample lib permission - com.my.lib.xml

<permissions>
    <library
        name="com.my.lib"
        file="/system/framework/com.my.lib.jar" />
</permissions>

library definition을 정의한, 위의 xml을 이용하면면, 해당 library를 system에 install하고, uses-library tag - AndroidManifest.xml - 를 이용해서 loading할 수 있게 된다.

Example uses-library

<uses-library
    android:name="com.my.lib"
    android:required="true" />

Sample Android.mk

LOCAL_PATH:= $(call my-dir)

# lib def
# -------
include $(CLEAR_VARS)
LOCAL_MODULE := com.my.lib.xml
LOCAL_MODULE_TAGS := optional
LOCAL_MODULE_CLASS := ETC
LOCAL_MODULE_PATH := $(TARGET_OUT_ETC)/permissions
LOCAL_SRC_FILES := $(LOCAL_MODULE)
include $(BUILD_PREBUILT)

# the library
# -----------
include $(CLEAR_VARS)
LOCAL_MODULE := com.my.lib
LOCAL_MODULE_TAGS := optional
LOCAL_MODULE_CLASS := JAVA_LIBRARIES
LOCAL_SRC_FILES := $(call all-subdir-java-files)
include $(BUILD_JAVA_LIBRARY)

# the package
# -----------
include $(CLEAR_VARS)
LOCAL_MODULE := myApk
LOCAL_MODULE_TAGS := optional
LOCAL_MODULE_CLASS := APPS
LOCAL_MODULE_SUFFIX := $(COMMON_ANDROID_PACKAGE_SUFFIX)
LOCAL_CERTIFICATE := platform
LOCAL_SRC_FILES := $(LOCAL_MODULE).apk
LOCAL_REQUIRED_MODULES := com.my.lib.xml com.my.lib
include $(BUILD_PREBUILT)

Explanation

* Product가 myApk 를 설치한다면, 위의 두 module 역시 설치하도록 하기 위해서 LOCAL_REQUIRED_MODULES 를 사용한다.

* Android framework은 library, feature 등을 등록하기위해서, $(TARGET_OUT_ETC)/permissions/*.xml 을 scan한다.


이렇게 하면, myApk가 load될때, uses-library 에 기록된, com.my.lib 이 같이 load된다.
단, system class loader는 여전히 BOOTCLASSPATH를 기준으로 하고 있고, Application context가 제공하는 class loader를 사용해야 위의 library가 load된 class loader를 사용할 수 있다.

다시 말하면, library에 정의된 class를 loading하기 위한 방법/예 는 아래와 같다.(class loader를 이용한 것은 example을 보여주기 위한 것 뿐, 그냥 원하는 class를 import해서 사용해도 된다. - 이미 load된 class 이므로...)

ClassLoader cloader; // cloader = new PathClassLoader("/system/framework/com.my.lib.jar", ClassLoader.getSystemClassLoader()); => (*A) // cloader = ClassLoader.getSystemClassLoader(); => (*B) // cloader = getApplicationContext().getClassLoader(); => (*C) cloader.loadClass("com.my.lib.SampleClass");


*A, *C : 정상적으로 SampleClass가 loading 됨.

*B : SampleClass를 load할 수 없음.

Done.



* First of all, check your kernel configuration.

- CONFIG_MODULES=y
- CONFIG_MODULE_UNLOAD=y    <- Optional

* Create your Kernel module code and Makefile


If you have luck, everything should be OK. But...


CASE: error at insmod?

insmod: init_module 'hello.ko' failed (Exec format error) in android
kernel message : unknown relocation: 27
Hmm, then you should check kernel functions you are using in the module (ex. printk)
You can check relocation type with following command (ex. printk)

readelf -r hello.ko | grep prink

Then, result may like below

xxxxxxxx  xxxxxxxx R_ARM_PLT32       00000000   printk

For your information : number 27 indicates R_ARM_PLT32.

Then, what's the problem?
ELF for the ARM Architecture(IHI0044E_aaelf.pdf) says that R_ARM_PLT32 is deprecated.
And, Linux kernel doesn't handle R_ARM_PLT32 at module.c : apply_relocation() function
We have two workaround for this issue.

* Update toolchains.
In my case, I faced this issue when I used gcc-4.4.3. And, gcc-4.7 resolved this issue.
(You can see, relocation type is changed into R_ARM_CALL instead of R_ARM_PLT32.)

* fpic / fno-pic HACK.
If you are in trouble with upgrading your toolchains, here is workaround (tested on gcc-4.4.3).
Add, -fpic or -fno-pic at CFLAGS_MODULE in your module Makefile like below.

make CFLAGS_MODULE=-fpic xxxx modules

Then, like above - updating toolchains -, relocation type is changed :-)



Code...


#!/bin/bash

if [[ x$1 = x ]]; then
    f=${1:-/proc/${$}/fd/0}
else
    f=$1
fi

while read line
do
    echo $line
done < $f


[ Tested on Android 4.4_r1 with 3.4 goldfish kernel ]


android NDK의 경우 alloc하지 않은 메모리를 free하더라도 allocate된 영역이라면, 에러(segmentation fault)를 발생시키지 않는것 같다.

물론 그렇다고해서 정상적으로 free된다는 뜻은 아니다. 아래의 code와 비슷한  형태로 test code를 만들고, 실험해 보면, 메모리 leak이 발생하고 있음을 쉽게 알 수 있다.

test code는 아래와 같다.

#include <stdio.h> #include <stdlib.h> int main(int argc, const char *argv) { char *p = malloc(4096 * 5); p += 2 * 4096; free(p); // <= error가 발생하지 않음. 그렇다고 해서 free되는 것도 아님. p+=10000000; free(p); // <= "[1] + Stopped (signal)" 발생... (이게 기대했던 건데...) return 0; }

쩝....

이건, Device의 libc에서 지원해 줘야 하는데, bionic의 dlmalloc compile option에서 'DEBUG' option을 켤 경우, 이 문제가 해결된다...

뭐.. 속도를 위해서 희생한 거니... 어쩔 수 없다지만... 그래도 아쉽긴... 아쉽다...

<< DEBUG switch 켜기 >>

diff --git a/libc/upstream-dlmalloc/malloc.c b/libc/upstream-dlmalloc/malloc.c
index 3ef9b61..9efc27d 100644
--- a/libc/upstream-dlmalloc/malloc.c
+++ b/libc/upstream-dlmalloc/malloc.c
@@ -520,7 +520,7 @@ MAX_RELEASE_CHECK_RATE   default: 4095 unless not HAVE_MMAP
   disable, set to MAX_SIZE_T. This may lead to a very slight speed
   improvement at the expense of carrying around more memory.
 */
-
+#define DEBUG 1 /* YHCHO test */
 /* Version identifier to allow people to support multiple versions */
 #ifndef DLMALLOC_VERSION
 #define DLMALLOC_VERSION 20806


아래의 간단한 layout xml을 보자...


<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"

    xmlns:tools="http://schemas.android.com/tools"

    android:layout_width="match_parent"

    android:layout_height="match_parent"

    android:paddingBottom="@dimen/activity_vertical_margin"

    android:paddingLeft="@dimen/activity_horizontal_margin"

    android:paddingRight="@dimen/activity_horizontal_margin"

    android:paddingTop="@+id/button" <=== 여기

    tools:context=".MainActivity" >

    <Button

        android:id="@+id/button"

        android:layout_width="wrap_content"

        android:layout_height="wrap_content"

        android:text="say hello" />

</RelativeLayout>



자... paddingTop에는 당연히 dimension이 들어가야 한다. 그런데... 일부로 엉뚱하게도 '@+id/button'을 넣어봤다.

그런데.. compile error가 발생하지 않는다.!

resource compiler가 실제 id를 찾아서 id의 type을 읽어서 판단해 주지는 못하는 것으로 보인다.

대신 runtime에 아래와 같은 error를 발생시킨다.


11-09 02:47:49.750: E/AndroidRuntime(975): FATAL EXCEPTION: main

11-09 02:47:49.750: E/AndroidRuntime(975): Process: com.example.ttstest, PID: 975

11-09 02:47:49.750: E/AndroidRuntime(975): java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.ttstest/com.example.ttstest.MainActivity}: android.view.InflateException: Binary XML file line #1: Error inflating class android.widget.RelativeLayout

11-09 02:47:49.750: E/AndroidRuntime(975): at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2176)

11-09 02:47:49.750: E/AndroidRuntime(975): at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2226)

11-09 02:47:49.750: E/AndroidRuntime(975): at android.app.ActivityThread.access$700(ActivityThread.java:135)

11-09 02:47:49.750: E/AndroidRuntime(975): at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1397)

11-09 02:47:49.750: E/AndroidRuntime(975): at android.os.Handler.dispatchMessage(Handler.java:102)

11-09 02:47:49.750: E/AndroidRuntime(975): at android.os.Looper.loop(Looper.java:137)

11-09 02:47:49.750: E/AndroidRuntime(975): at android.app.ActivityThread.main(ActivityThread.java:4998)

11-09 02:47:49.750: E/AndroidRuntime(975): at java.lang.reflect.Method.invokeNative(Native Method)

11-09 02:47:49.750: E/AndroidRuntime(975): at java.lang.reflect.Method.invoke(Method.java:515)

11-09 02:47:49.750: E/AndroidRuntime(975): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:777)

11-09 02:47:49.750: E/AndroidRuntime(975): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:593)

11-09 02:47:49.750: E/AndroidRuntime(975): at dalvik.system.NativeStart.main(Native Method)

11-09 02:47:49.750: E/AndroidRuntime(975): Caused by: android.view.InflateException: Binary XML file line #1: Error inflating class android.widget.RelativeLayout

11-09 02:47:49.750: E/AndroidRuntime(975): at android.view.LayoutInflater.createView(LayoutInflater.java:620)

11-09 02:47:49.750: E/AndroidRuntime(975): at com.android.internal.policy.impl.PhoneLayoutInflater.onCreateView(PhoneLayoutInflater.java:56)

11-09 02:47:49.750: E/AndroidRuntime(975): at android.view.LayoutInflater.onCreateView(LayoutInflater.java:669)

11-09 02:47:49.750: E/AndroidRuntime(975): at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:694)

11-09 02:47:49.750: E/AndroidRuntime(975): at android.view.LayoutInflater.inflate(LayoutInflater.java:469)

11-09 02:47:49.750: E/AndroidRuntime(975): at android.view.LayoutInflater.inflate(LayoutInflater.java:397)

11-09 02:47:49.750: E/AndroidRuntime(975): at android.view.LayoutInflater.inflate(LayoutInflater.java:353)

11-09 02:47:49.750: E/AndroidRuntime(975): at com.android.internal.policy.impl.PhoneWindow.setContentView(PhoneWindow.java:290)

11-09 02:47:49.750: E/AndroidRuntime(975): at android.app.Activity.setContentView(Activity.java:1928)

11-09 02:47:49.750: E/AndroidRuntime(975): at com.example.ttstest.MainActivity.onCreate(MainActivity.java:23)

11-09 02:47:49.750: E/AndroidRuntime(975): at android.app.Activity.performCreate(Activity.java:5243)

11-09 02:47:49.750: E/AndroidRuntime(975): at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1087)

11-09 02:47:49.750: E/AndroidRuntime(975): at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2140)

11-09 02:47:49.750: E/AndroidRuntime(975): ... 11 more

11-09 02:47:49.750: E/AndroidRuntime(975): Caused by: java.lang.reflect.InvocationTargetException

11-09 02:47:49.750: E/AndroidRuntime(975): at java.lang.reflect.Constructor.constructNative(Native Method)

11-09 02:47:49.750: E/AndroidRuntime(975): at java.lang.reflect.Constructor.newInstance(Constructor.java:423)

11-09 02:47:49.750: E/AndroidRuntime(975): at android.view.LayoutInflater.createView(LayoutInflater.java:594)

11-09 02:47:49.750: E/AndroidRuntime(975): ... 23 more

11-09 02:47:49.750: E/AndroidRuntime(975): Caused by: java.lang.UnsupportedOperationException: Can't convert to dimension: type=0x12

11-09 02:47:49.750: E/AndroidRuntime(975): at android.content.res.TypedArray.getDimensionPixelSize(TypedArray.java:464)

11-09 02:47:49.750: E/AndroidRuntime(975): at android.view.View.<init>(View.java:3560)

11-09 02:47:49.750: E/AndroidRuntime(975): at android.view.View.<init>(View.java:3475)

11-09 02:47:49.750: E/AndroidRuntime(975): at android.view.ViewGroup.<init>(ViewGroup.java:464)

11-09 02:47:49.750: E/AndroidRuntime(975): at android.widget.RelativeLayout.<init>(RelativeLayout.java:236)

11-09 02:47:49.750: E/AndroidRuntime(975): ... 26 more



쩝... layout을 작성할때는.. 항상 조심하자...

compiler가 이런걸 걸러주지 못하니... 조심스럽게 작성해야 할 수 밖에...

Creating libraries - Static library, shared library

NOTE : In case jni shared library, 'jni' code should in shared library source code. That is, you can put all other source codes in static library, but 'jni' should NOT in static library source

[ Android.mk ] for libraries for NDK.

LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS) LOCAL_MODULE := libX LOCAL_SRC_FILES := src0.c src1.c ... LOCAL_CFLAGS += LOCAL_C_INCLUDES += include $(BUILD_STATIC_LIBRARY) include $(CLEAR_VARS) LOCAL_MODULE := libXS LOCAL_SRC_FILES := jni.c LOCAL_CFLAGS += LOCAL_C_INCLUDES += LOCAL_STATIC_LIBRARIES := libX include $(BUILD_SHARED_LIBRARY)

Now you can find

shared library in <project root>/libs/armeabi/

static library in <project root>/obj/local/armeabi/



Creating executable with prebuilt static library (ex. static library built above - libX.a)


[ Android.mk ] for libraries for NDK.

LOCAL_PATH := $(call my-dir) ####################################################### # ####################################################### include $(CLEAR_VARS) LOCAL_MODULE := myexe LOCAL_SRC_FILES := main.c LOCAL_CFLAGS := LOCAL_LDFLAGS := LOCAL_C_INCLUDES += LOCAL_LDLIBS := -L <example/above/libX/project/root>/obj/local/armeabi/ -lX include $(BUILD_EXECUTABLE)

Now you can get 'myexe' executable.


Some notable points when using mmap 

- mapping with MAP_PRIVATE doesn't carry updates through to the underlying file.

- mmap writing to file is deferred.

=> use msync to write back to file at certain time.

- See also, mprotect, madvise ...


mmap and memory(smaps).

protection argument and flag of mmap matches vma flags (ex. MAP_PRIVATE + PROT_READ | PROT_EXEC <=> r-xp )


* mmap to generic file
Writing to mapped memory doesn't increase process's memory usage(RSS) - doesn't request process's memory page.(I think just memory for disk cache is affected by this operation.)


* mmap to anonymous - MAP_PRIVATE
Demanded pages are treated as PrivateDirty (just like malloc)


map = mmap(NULL, mapsz, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);


there is only one VMA(size = mapsz) - Virtual Memory Area - for this map. And it's flag will be ---p.


mprotect(map, mapsz / 3, PROT_WRITE);


Now, two VMAs are used for this map.
One(vma0) is VMA(-w-p) whose size is mapsz / 3. The other(vma1) is VMA(---p) whose size is mapsz / 3 * 2.


sz = mapsz / 3; while (sz--) map[sz] = 0xff;


Now, vma0 has PrivateDirty (size = mapsz / 3) because pages are demanded and written.

* mmap to anonymous - MAP_SHARED   
Same with above. But, shared flag is used instead of private flag.
And in case of shared memory, PSS is very valuable information along with RSS.

(to be continued...)

ARM의 FSR(Fault Status Register) Spec을 보면

ARM9 까지는 Read/Write 상태를 알 수 없고 , ARM11부터 지원하는 것 처럼 보인다 - (1 << 11 bit - Linux kernel "fault.h")

그렇다면, ARM9에서 CoW는 어떤식으로 지원되었을까?

자세히 살펴보지는 않았지만, vendor에서 지원했거나, 아니면, MMU에서 해당 정보를 알 수 있는 방법을 제공했을 수도 있겠다.

(아니면... 내가 모르는 무언가가 있을수도...)

어쨌든 CoW는 memory write순간을 Processor가 알 수 있어야만 구현이 가능하다!

'Domain > Linux' 카테고리의 다른 글

Read line from file or standard input....  (0) 2013.11.28
[Linux] mmap and memory...  (0) 2013.10.07
git server daemon 설치하기  (0) 2013.06.13
atime 대신에 strictatime을 사용하자!  (0) 2013.05.31
[Shell] Variable Name Expansion  (0) 2013.03.28

보통 Eclipse에서 Javadoc을 사용하기 위해서는 아래의 링크를 참조하면 된다.

http://stackoverflow.com/questions/9873152/how-to-attach-javadoc-or-sources-to-jars-in-libs-folder


그렇지만, ADT의 경우는 약간 다르다.

위의 링크를 자세히 살펴보면... 아래쪽에 ADT의 경우 libs directory를 사용하면 안된다는 내용의 minor 답변을 볼 수 있을 것이다.

그렇다!

ADT의 경우는 libs directory를 일반적은 Eclipse와는 달리 사용하는 듯 하다.

따라서, ADT에서 javadoc을 사용하기 위해서는 libs directory가 아닌 다른 외부 directory를 만들어서 Add JARs 메뉴를 통해서 jar archive를 build path에 추가해야 한다. 그 다음, 해당  jar archive가 project의 Referenced Libraries 아래에 정상적으로 추가되었는지 확인한다.

위의 과정이 정상적으로 이루어 졌다면, 위의 stackoverflow 에서의 답변(ADT관련 답변) 에서 언급한 대로


해당 jar archive 선택 -> 우클릭 -> Properties 선택 -> Javadoc Location 메뉴 선택 -> javadoc location을 입력 -> project close -> project open (reopen)


과정을 거치면, java doc이 정상적으로 동작하는 것을 확인할 수 있다.

Tested on Android ICS.


- Making Android project that has normal java entry function - 'public static void main(String[] args) { ...  }'.

  (ex. make 'public static void main(String[] args) { ... }' at 'my.test.Main' )

my/test/Main.java

-----------------


    package my.test;

public static void main(String[] args) {

System.out.println("Hello!");

}

- Making 'xxx.apk' by exporting Android project. (You don't need to care about signing.)

- Let's test with following commands

    $> adb push xxx.apk /data

And then programs can be run with following commands

    $> export CLASSPATH=/data/xxx.apk
    $> app_process /system/bin my.test.Main
or
    $> export CLASSPATH=/data/xxx.apk
    $> dalvikvm my.test.Main
or
    $> dalvikvm -classpath /data/mytest.apk my.test.Main

'main' function should be run.


IMPORTANT POINT here is knowing that 'apk' is a kind of 'jar' in JAVA.

See inside 'apk', then you can figure out structure of 'apk' is very similar with 'jar'.

And this is the hint of above way.


And, you can also find classes.dex at <android project root>/bin/ . and this is just like classes.jar of java.

So, this classes.dex can be replace xxx.apk above.


WARNING!



+ Recent posts