가장 따뜻한 11월 에 나온 ndk 7이다.

Linux 32/64-bit (x86) android-ndk-r7-linux-x86.tar.bz2


android nkd 7을 다운받아서 ndk 해보는데. 잘 안된다.  구글 검색해도 안나와서.. 좀 열받는다.

ndk 빌드하면 이렇게 아래로 나오는데..

/work/android-ndk-r7/samples/san-angeles# ../../ndk-build
/work/android-ndk-r7/prebuilt/linux-x86/bin/awk: 1: ELF : not found
/work/android-ndk-r7/prebuilt/linux-x86/bin/awk: 4: Syntax error: word unexpected (expecting ")")
Android NDK: Host 'awk' tool is outdated. Please define HOST_AWK to point to Gawk or Nawk !   
/work/android-ndk-r7/build/core/init.mk:258: *** Android NDK: Aborting.    .  Stop.



추적을 해보니. 어라. awk 문법에 맞는 것이 동작이 안된다.

/work/android-ndk-r7/samples/san-angeles# ../../build/awk/check-awk.awk
../../build/awk/check-awk.awk: line 22: BEGIN: command not found
../../build/awk/check-awk.awk: line 26: syntax error near unexpected token `s1,"world"'
../../build/awk/check-awk.awk: line 26: `    if (! match(s1,"world")) {'


awk도 최신 버전인데..

# apt-get install awk
Reading package lists... Done
Building dependency tree      
Reading state information... Done
Package awk is a virtual package provided by:
  original-awk 2010-05-23-1
  mawk 1.3.3-15ubuntu2
  gawk 1:3.1.7.dfsg-5

 




mk 파일보면서 android -ndk에 awk가 이상이 있나 확인해보았다.

32비트 x86 버전에서 prebuild/linux-x86/bin/awk 파일은 64 비트용이었다... 아하~

/work/android-ndk-r7/prebuilt/linux-x86/bin# file awk
awk: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.15, stripped


awk 파일을 지우고 gawk를 링크를 걸어준다.

/work/android-ndk-r7/prebuilt/linux-x86/bin# mv awk awk.old
/work/android-ndk-r7/prebuilt/linux-x86/bin# ln -s /usr/bin/gawk awk

그리고, 샘플 디렉토리 가서 테스트해보니. 오예~ 빌드 완료.

/work/android-ndk-r7/samples/hello-jni# ../../ndk-build
Gdbserver      : [arm-linux-androideabi-4.4.3] libs/armeabi/gdbserver
Gdbsetup       : libs/armeabi/gdb.setup
Compile thumb  : hello-jni <= hello-jni.c
SharedLibrary  : libhello-jni.so
Install        : libhello-jni.so => libs/armeabi/libhello-jni.so
Posted by '김용환'
,


http://developer.android.com/sdk/index.html 에 밑에 보면,
ndk 를 다운받을 수 있다.


mac, window(cygwin 이용), linux 버전있는데, linux로 설치해본다.


ndk7이 4.0을 포함한 최신 버전이지만, ubuntu10. 11에서 awk 관련해서 버그가 있다. 32비트에서만 이슈가 있음. 이 부분에 대한 해결방법은 여기에 있다.

나는 ndk 6b를 사용했지만, 위의 7도 동일하게 사용할 수 있다.


리눅스(ubuntu)에 android-ndk-r6b.tar.gz을 설치한다.
tar jxvf android-ndk-r6b.tar.gz

설치는 완료했다.

이제 코드쪽을 본다.
이클립스에서 클래스 하나를 생성하고, jni 함수를 하나를 만들고, 동적 library를 읽도록 한다.

package com.google;

import android.app.Activity;
import android.os.Bundle;
import android.widget.TextView;

public class HelloJni extends Activity {
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
  TextView tv = new TextView(this);
  tv.setText(stringFromJNI());
  setContentView(tv);
    }
    public native String stringFromJNI();
 static {
  System.loadLibrary("hello-jni");   
 }

}




이클립스 workspace의 프로젝트에서 컴파일된 디렉토리로 들어가서
class파일을 통해서 header 파일을 만든다.

프로젝트이름\bin> javah -classpath . com.google.JniHello

그러면, header 파일이 생성된 것을 확인할 수 있다.

> dir
com_google_JniHello.h

이 파일을 이용해서 c 소스를 만든다.

#include <string.h>
#include <jni.h>


jstring
Java_com_google_HelloJni_stringFromJNI( JNIEnv* env,
                                                  jobject thiz )
{
    return (*env)->NewStringUTF(env, "Hello from JNI !");
}




이 파일을 linux에 설치한 ndk에 특정 위치에 둔다.

설치디렉토리/jni-test/knight/jni 폴더에 둔다.
그리고, make 파일인 Android.mk도 같이 집어 넣는다.

Android.mk 파일은 다음과 같다.

# Copyright (C) 2009 The Android Open Source Project
#
# 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    := hello-jni
LOCAL_SRC_FILES := hello-jni.c

include $(BUILD_SHARED_LIBRARY)




 



설치디렉토리/jni-test/knight/ 디렉토리에서 빌드한다.

설치디렉토리/jni-test/knight # ../../ndk-build

컴파일이 잘되면 이렇게 so 파일이 나온다.
설치디렉토리/jni-test/knight/libs/armeabi/libhello-jni.so 파일이 생성된다.




so파일을 이클립스단으로 복사한다.
그 전에 먼저 jni 파일과 mk 파일을 복사한다.

eclipse 프로젝트의 jni 폴더를 생성하고, jni와 mk 파일을 복사한다.
그리고, so 파일을 libs에 복사한다.
디렉토리는 이렇게 나와야 한다.




이 파일에 대해서 에뮬에서 run하면 다음과 같은 결과가 나온다.




그리고, 보드에다가도 테스트해봤다.
ok 잘돈다.




소스는 아래와 같다.




ndk 를 보면, sample 디렉토리 밑에 많은 샘플(open gl 외 다양한 예제) 들이 있다.
참조해서 만들어보면 좋다.

san-angles 라는 샘플은 움직이는 예제를 보여준다. 터치해주면 잠깐 멈추고 그러니. 테스트하기에 재미있는 예제이다.



* 레퍼런스
 http://developer.android.com/sdk/ndk/index.html 

Posted by '김용환'
,

혼자 잡담) java-jni-cpp 가지고 300만원짜리 알바까지 했는데..
왠걸 다시 하니 기억이 안난다. 오홋 새록새록해~ 그래도 어떻게 하나 열심히 공부해야지~^^




정리하는 내용
- 리눅스에서 java->c 호출
- 리눅스에서 c->java 호출


그래픽이나 c/c++로 만들어진 라이브러리들을 바로 사용할 수 있도록 하는 프레임웤이다.

HelloJNI 테스트 해본다.

class HelloJNI {
 native void printHello();
 native void printString(String str);
 
 static {
  System.load("/work/JniTest/hellojni.so");
 }
 public static void main(String[] args) {
  HelloJNI myJNI = new HelloJNI();
  myJNI.printHello();
  myJNI.printString("Hello in C");
 }
}



삼바를 이용해서 리눅스 /work/JniTest 디렉토리를 생성하고,  HelloJNI.java 복사한다.

컴파일하고, 그  class 파일을 이용해서 header 파일을 생성하도록 한다.
javac HelloJNI.java
javah HelloJNI


HelloJNI.h 파일이 생성

/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class HelloJNI */

#ifndef _Included_HelloJNI
#define _Included_HelloJNI
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     HelloJNI
 * Method:    printHello
 * Signature: ()V
 */
JNIEXPORT void JNICALL Java_HelloJNI_printHello
  (JNIEnv *, jobject);

/*
 * Class:     HelloJNI
 * Method:    printString
 * Signature: (Ljava/lang/String;)V
 */
JNIEXPORT void JNICALL Java_HelloJNI_printString
  (JNIEnv *, jobject, jstring);

#ifdef __cplusplus
}
#endif
#endif






HelloJNI.c 소스를 생성

#include "HelloJNI.h"

JNIEXPORT void JNICALL Java_HelloJNI_printHello(JNIEnv *env, jobject obj) {
 printf("Hello World !!! jni\n");
}


JNIEXPORT void JNICALL Java_HelloJNI_printString(JNIEnv *env, jobject obj, jstring string) {
  const char *str = (*env)->GetStringUTFChars(env,string,0);
  printf("%s\n", str);
  return;
}





컴파일을 하여 so 파일이 만들어지도록 한다.

# gcc -c -I$JAVA_HOME/include -I$JAVA_HOME/include/linux HelloJNI.c
# gcc -shared -o HelloJNI.so HelloJNI.o
# ls -al HelloJNI.so
HelloJNI.so

 정상적으로 동작된다.

# java HelloJNI
Hello World !!!
Hello in C!!!

 


이런식으로 표현한 다양한 방식을 샘플로 적어본다.

java 코드

class JniFuncMain {
..
public static native JniTest createJniObject();
..
}

 

class JniTest
{
 private int intField;
 
 public JniTest(int num)
 {
  intField = num;
 }
 
 public int callByNative(int num)
 {
  return num;
 }
 
 public void callTest()
 {
  System.out.println("intField=" + intField);
 }
}



 cpp 코드


#include <jni.h>
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     JniFuncMain
 * Method:    createJniObject
 * Signature: ()LJniTest;
 */
JNIEXPORT jobject JNICALL Java_JniFuncMain_createJniObject
  (JNIEnv *env, jclass clazz)
{
 jclass targetClass;
 jmethodID mid;
 jobject newObject;
 jstring helloStr;
 jfieldID fid;
 jint staticIntField;
 jint result;
 
 // Get the Class staticIntField Value
 fid = env->GetStaticFieldID(clazz, "staticIntField", "I");
 staticIntField = env->GetStaticIntField(clazz, fid);
 printf("[CPP] Get JniFuncMain_Class_staticIntField!!\n");
 printf("[CPP] JniFuncMain_Class_staticIntField = %d\n", staticIntField);
 
 // Find the Class to create object
 targetClass = env->FindClass("JniTest");
 
 // Find the Constructor
 mid = env->GetMethodID(targetClass, "<init>", "(I)V");
 
 // Create a JniTest Object
 printf("[CPP] JniTest_Object Create!!\n");
 newObject = env->NewObject(targetClass, mid, 100);
 
 // Call the Method of Object
 mid = env->GetMethodID(targetClass, "callByNative", "(I)I");
 result = env->CallIntMethod(newObject, mid, 200);
 
 // Set the intField_field of JniObject
 fid = env->GetFieldID(targetClass, "intField", "I");
 env->SetIntField(newObject, fid, result);
 
 // return created Object
 return newObject;
}
#ifdef __cplusplus
}
#endif
 


# g++ -I/$JAVA_HOME/include -I/$JAVA_HOME/include/linux -c jnifunc.cpp
# g++ -shared -o jnifunc.so jnifunc.o
# java 메인클래스실행




이외에 c에서 java로도 호출이 가능하게 할 수 있다.


#include <jni.h>

int main()
{
 JNIEnv *env;
 JavaVM *vm;
 JavaVMInitArgs vm_args;
 JavaVMOption options[1];
 jint res;
 jclass cls;
 jmethodID mid;
 jstring jstr;
 jclass stringClass;
 jobjectArray args;
 
 // 1.JVM에 넘겨줄 아규먼트 셋팅 
 options[0].optionString = "-Djava.class.path=.";
 vm_args.version = 0x00010002;
 vm_args.options = options;
 vm_args.nOptions = 1;
 vm_args.ignoreUnrecognized = JNI_TRUE;
 
 //2.JVM 생성
 res = JNI_CreateJavaVM(&vm, (void**)&env, &vm_args);
 
 //3. 클래스 검색 과 로딩
 cls = (*env)->FindClass(env, "InvocationApiTest");
 
 //4. main 메소드 얻어오기 
 mid = (*env)->GetStaticMethodID(env, cls, "main", "([Ljava/lang/String;)V");
 
 //5.메인메소드의 실제 파라미터값을 지정한다. 
 jstr = (*env)->NewStringUTF(env, "Hello Test from Native!!!");
 stringClass = (*env)->FindClass(env, "java/lang/String");
 args = (*env)->NewObjectArray(env, 1, stringClass, jstr);
 
 //6.main 메소드를 호출한다.
 (*env)->CallStaticVoidMethod(env, cls, mid, args);
 
 //7.JVM를 내린다.
 (*vm)->DestroyJavaVM(vm);
}




클래스 파일

public class InvocationApiTest
{
 public static void main(String[] args)
 {
  System.out.println(args[0]);
 }
}


# gcc -I/$JAVA_HOME/include -I$JAVA_HOME/include/linux -c invocationApi.c

그다음은 jvm 관련 항목을 링크 옵션으로 줘야 jvm이 실행할 수 있다.
# gcc -L$JAVA_HOME/jre/lib/i386/client invocationApi.o -ljvm
(libjvm.so 라는 파일이 $JAVA_HOME/jre/lib/i386/client/libjvm.so 파일이 있어야 한다.)

dependent한 library 가 있는지를 확인한다.

# ldd a.out 

# export LD_LIBRRARY_PATH=$LD_LIBRARY_PATH:$JAVA_HOME/jre/lib/i386/client

# a.out
결과 출력


다음예는
jni onload 함수를 오버라이딩해서,
a라고 하는 함수를 b라는 함수로 호출되도록 바꿔치기 를 할 수 있는 예제이다.


// hellojnimap.cpp

#include <jni.h>
#include <stdio.h>

void printHelloNative(JNIEnv *env, jobject obj);
void printStringNative(JNIEnv *env, jobject obj, jstring string);

// JNI_ONload는 오버라이딩한 것이다.
JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved)
{
 JNIEnv *env = NULL;
 JNINativeMethod nm[2];
 jclass cls;
 jint result = -1;
 
 if(vm->GetEnv((void**)&env, JNI_VERSION_1_4) != JNI_OK) {
  printf("Error");
  return JNI_ERR;
 }
 
 cls = env->FindClass("HelloJNI");
 
 nm[0].name = (char*)"printHello";
 nm[0].signature = (char*)"()V";
 nm[0].fnPtr = (void *)printHelloNative;
 
 nm[1].name = (char*)"printString";
 nm[1].signature = (char*)"(Ljava/lang/String;)V";
 nm[1].fnPtr = (void *)printStringNative;
 
 env->RegisterNatives(cls, nm, 2);
 
 return JNI_VERSION_1_4;
}

void printHelloNative(JNIEnv *env, jobject obj)
{
 printf("Hello World in C++!!\n");
 return;
}

void printStringNative(JNIEnv *env, jobject obj, jstring string)
{
 //const char *str = (*env)->GetStringUTFChars(env, string, 0);
 const char *str = env->GetStringUTFChars(string, 0);
 printf("%s\n", str);
 return;
}

#if 0
JNIEXPORT void JNICALL Java_HelloJNI_printHello
  (JNIEnv *env, jobject obj)
{
 printf("Hello World in C!!\n");
 return;
}

JNIEXPORT void JNICALL Java_HelloJNI_printString
  (JNIEnv *env, jobject obj, jstring string)
{
 const char *str = (*env)->GetStringUTFChars(env, string, 0);
 printf("%s\n", str);
 return;
}
#endif





//HelloJNI.java

class HelloJNI
{
 native void printHello();
 native void printString(String str);
 
 static {
  System.load("/work/JniTest/hellojnimap.so");
 }
 
 public static void main(String[] args) {
  HelloJNI myJNI = new HelloJNI();
  
  myJNI.printHello();
  myJNI.printString("Hello from c!!");
 }
 
}




# g++ -I/$JAVA_HOME/include -I$JAVA_HOME/include/linux -c hellojnimap.cpp
# g++ -shared -o hellojnimap.so hellojnimap.o
# java 메인클래스실행

Posted by '김용환'
,


안드로이드 버전에 탑재된 리눅스 커널 버전을 확인하기 위해서는 위키(http://en.wikipedia.org/wiki/Android_version_history)를 통해 확인할 수 있다.

만약 내가 누군가의 모바일 에서 리눅스 커널 버전을 application으로 확인하기 위한 앱 소스는 다음과 같다.


간단 소스


package com.google;

import android.app.Activity;
import android.os.Bundle;
import android.widget.TextView;

public class OSFinderActivity extends Activity {
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        TextView tv = new TextView(this);
        tv.setText(System.getProperty("os.version"));
        setContentView(tv);
    }
}




리눅스 커널 버전을 확인






소스에서도 리눅스 커널을 보고 싶다.

froyo는 kernel/Makefile을 보면 확인이 가능하다.

VERSION = 2
PATCHLEVEL = 6
SUBLEVEL = 32
EXTRAVERSION = .9

공식문서에 있는 2.6.32 가 맞다.
http://developer.android.com/sdk/android-2.2-highlights.html



진저브레드는 kernel 디렉토리가 없어서 grep 으로 찾아보니. 아래 파일에서 2.6.32 로 나온다.
system/core/ThirdPartyProject.prop

공식문서에서는 2.6.35인데.. ^^;;;
http://developer.android.com/sdk/android-2.3-highlights.html


아이스크림 샌드위치는 공식적으로 커널 버전에 대한 내용은 없다. (현재 2011.11월 말)
다만, 아래 엔가젯에서 "but it's running on an updated build (IRK48) and kernel (3.0.1).
" 이라는 내용이 언급되어 있을 뿐이다.

http://www.engadget.com/2011/09/28/ice-cream-sandwich-gets-a-two-minute-tour-courtesy-of-a-lucky-e/
 



Posted by '김용환'
,

다음 디렉토리 지운다.

(xp)
C:\Documents and Settings\사용자계정\.android

또는

(win7)
사용자 user 디렉토리\사용자계정\.android

Posted by '김용환'
,


> adb shell
간단한 명령어
# pwd
# cd /
# ls
# ps
# netstat
# getprop

property 지정 (init 프로세스에서 property의 변경사항을 모니터링하다가 ctl.start나 ctl.stop이 오면 service를 시작 또는 종료한다.)

 # setprop ctl.start bootanim
setprop ctl.start bootanim
# setprop ctl.stop bootadnim
setprop ctl.stop bootadnim

참고
특별히 고치지 않은 버전에서의 root/init.rc 파일 에는 다음 설정이 있다.
service bootanim /system/bin/bootanimation
    user graphics
    group graphics
    disabled
    oneshot 

이미 서비스로 등록되어 있는 bootanimation을 내리고 올리는 작업을 할 수 있다.



# getprop ro.debuggable
getprop ro.debuggable
1
# setprop ro.debuggable 0
setprop ro.debuggable 0

# getprop persist.service.adb.enable
getprop persist.service.adb.enable
1
# setprop persist.service.adb.enable 0
setprop persist.service.adb.enable 0
#
여기서 adb가 죽고, 튕겨나감
>adb shell
error: device not found

avd를 다시 실행한다.


>adb devices
List of devices attached
emulator-5554   device

>adb -s emulator-5554 get-state
device

>adb -d get-serialno
unknown


>adb -s emulator-5554 kill-server


>adb -s emulator-5554 start-server
* daemon not running. starting it now on port 5037 *
* daemon started successfully *


local 파일을 에뮬로 복사
>adb -s emulator-5554 push c:\1.jpg /data/1.jpg
689 KB/s (154474 bytes in 0.218s)


에뮬에 있는 apk 를 local로 복사
>adb -s emulator-5554 pull /data/app/ApiDemos.apk c:\ApiDemos.apk
212 KB/s (2409035 bytes in 11.093s)


export 해서 apk 만들기
http://blog.naver.com/minroud?Redirect=Log&logNo=80130874162

>adb -s emulator-5554 -e install HelloAndroid1.apk
140 KB/s (13515 bytes in 0.093s)
        pkg: /data/local/tmp/HelloAndroid1.apk
Success

(이클립스 데몬에서 올라가는 것 확인)

혹시 똑같은 apk가 있어서 설치가 안되면 강제로 설치하도록 함
(Failure [INSTALL_FAILED_ALREADY_EXISTS] 무시)

>adb -s emulator-5554 -e install -r  HelloAndroid1.apk
13 KB/s (13515 bytes in 1.000s)
        pkg: /data/local/tmp/HelloAndroid1.apk
Success

uninstall 할때는 패키지명으로 삭제해야 함
>adb -s emulator-5554 uninstall com.google.HelloAndroid

 

# service list
service list
Found 49 services:
0       phone: [com.android.internal.telephony.ITelephony]
1       iphonesubinfo: [com.android.internal.telephony.IPhoneSubInfo]
2       simphonebook: [com.android.internal.telephony.IIccPhoneBook]
3       isms: [com.android.internal.telephony.ISms]
4       diskstats: []
5       appwidget: [com.android.internal.appwidget.IAppWidgetService]
..

# service call activity 1598968902
service call activity 1598968902
Result: Parcel(
  0x00000000: 0000001c 006e0061 00720064 0069006f '....a.n.d.r.o.i.'
  0x00000010: 002e0064 00700061 002e0070 00410049 'd...a.p.p...I.A.'
  0x00000020: 00740063 00760069 00740069 004d0079 'c.t.i.v.i.t.y.M.'
  0x00000030: 006e0061 00670061 00720065 00000000 'a.n.a.g.e.r.....')
#
 

Posted by '김용환'
,



vmware에 ubuntu 운영체제에 안드로이드 소스 설치후에 소스를 볼라면, vi와 cscope의 달인이 아니면 보기가 너무 힘들다.  그래서, 삼바 서버를 설치해두면 두고 두고 쓰기 편하다.

삼바를 설치후, 소스 보는 것이 편해진다.



삼바 설치

$ sudo apt-get install samba smbfs

삼바 환경설정

$ sudo gedit /etc/samba/smb.conf
#   security = user
-> (수정)
   security = user

 

# By default, the home directories are exported read-only. Change the
# next parameter to 'no' if you want to be able to write to them.
;   read only = yes
-> (추가)
# By default, the home directories are exported read-only. Change the
# next parameter to 'no' if you want to be able to write to them.
;   read only = yes
writable = yes


;   create mask = 0700
-> (수정)
   create mask = 0700

;   directory mask = 0700
-> (수정)
   directory mask = 0700

;   valid users = %S
-> (수정)
   valid users = %S



#======================= Share Definitions =======================
바로 밑에 추가


[root]
comment = Root
path = /
browable = yes
writable = yes





환경 설정 확인
root 계정 접근을 확인한다.

$ sudo testparm


....
[root]
 comment = Root Directory
 path = /
 valid users = %S
 read only = No
 create mask = 0700
 directory mask = 0700

......


패스워드 설정

$ sudo smbpasswd -a root
New SMB password:
Retype new SMB password:
Added user root.


ip 확인

$ ifconfig
eth0      Link encap:Ethernet  HWaddr 00:0c:29:ff:fb:0a 
          inet addr:192.168.150.128


리눅스에서 나와 윈도우 탐색기에서 접근
패스워드는 smbpasswd에서 입력한 계정 paswd 가능하다.





repo로 받은 안드로이드 소스 보기가 편하다..




* 예전(7,8년 전)에는 삼바 설정 파일 수정후에 삼바 데몬을 재시작했는데..
ubuntu 에서 설치후에는 samba 설정 파일만 수정하면, 알아서 자동으로 읽는다.. 완전 신기.
그리고, 속도도 빨라졌다. 삼바가 이렇게 좋아질 줄이야!!!



그리고, 이클립스를 이용해서 소스를 확인할 때 볼 수 있는 소스를 복사해서 사용한다.
framework/base/core/java 밑에 있는 파일을 로컬로 복사한다. 그리고, 이클립스에서 안드로이드 소스에 해당되는 곳에 F3를 눌러 복사한 folder 로 지정하서 소스를 보면 끝..

\\ip\안드로이드소스받은위치\frameworks\base\core\java


네트웍 드라이드 연결을 할 수 도 있다.
윈도우 탐색기->도구->네트웍드라이브 연결

드라이브이름과 , \\192.168.158.128\root\work 각각 넣어주고 엔터하면 접근된다.

Posted by '김용환'
,
자바 클래스가 어떻게 되어 있는지 분석하려면, asm library를 써서 확인할 수 있다.
이외, 간단하게 콘솔로 출력할 수 있는 툴이 있어서 소개한다.

jcf-dump 라는 툴인데, gcc java를 설치하면 gcj와 함께 있는 툴이다.

http://linux.die.net/man/1/jcf-dump

Name

jcf-dump - print information about Java class files

Synopsis

jcf-dump [-c] [--javap] [--classpath=path] [--CLASSPATH=path] [-Idir...] [-o file] [--version] [--help] [-v] [--verbose] classname...


.............



gcj를 설치한다.
$ sudo apt-get install gcj-jdk

간단하게 클래스 파일을 만들어본다.

$ vi test.java
public class test {
    public static void main(String[] args) {
        int a = 0;
        String temp = "temp";
        a++;
        System.out.println("a:" + a);
    }
}



jcf-dump 를 이용하면, magic number 넘버가 나오고 compile(target)된 버전이 나온다. major_version이 50이면, jdk 1.6이라는 뜻이다.  그리고, Constant pool  정보, Fields, Methods 정보가 바로 나온다.

$ jcf-dump test
Reading .class from ./test.class.
Magic number: 0xcafebabe, minor_version: 0, major_version: 50.
Constant pool (count: 45):
#1: Methodref class: 12=java.lang.Object name_and_type: 21=<<init> ()void>
#2: String 22="temp"
#3: Fieldref class: 23=java.lang.System name_and_type: 24=<out java.io.PrintStream>
#4: Class name: 25="java/lang/StringBuilder"
#5: Methodref class: 4=java.lang.StringBuilder name_and_type: 21=<<init> ()void>
#6: String 26="a:"
#7: Methodref class: 4=java.lang.StringBuilder name_and_type: 27=<append (java.lang.String)java.lang.StringBuilder>
#8: Methodref class: 4=java.lang.StringBuilder name_and_type: 28=<append (int)java.lang.StringBuilder>
#9: Methodref class: 4=java.lang.StringBuilder name_and_type: 29=<toString ()java.lang.String>
#10: Methodref class: 30=java.io.PrintStream name_and_type: 31=<println (java.lang.String)void>
#11: Class name: 32="test"
#12: Class name: 33="java/lang/Object"
#13: Utf8: "<init>"
#14: Utf8: "()V"
#15: Utf8: "Code"
#16: Utf8: "LineNumberTable"
#17: Utf8: "main"
#18: Utf8: "([Ljava/lang/String;)V"
#19: Utf8: "SourceFile"
#20: Utf8: "test.java"
#21: NameAndType name: 13=<init>, signature: 14=()void
#22: Utf8: "temp"
#23: Class name: 34="java/lang/System"
#24: NameAndType name: 35=out, signature: 36=java.io.PrintStream
#25: Utf8: "java/lang/StringBuilder"
#26: Utf8: "a:"
#27: NameAndType name: 37=append, signature: 38=(java.lang.String)java.lang.StringBuilder
#28: NameAndType name: 37=append, signature: 39=(int)java.lang.StringBuilder
#29: NameAndType name: 40=toString, signature: 41=()java.lang.String
#30: Class name: 42="java/io/PrintStream"
#31: NameAndType name: 43=println, signature: 44=(java.lang.String)void
#32: Utf8: "test"
#33: Utf8: "java/lang/Object"
#34: Utf8: "java/lang/System"
#35: Utf8: "out"
#36: Utf8: "Ljava/io/PrintStream;"
#37: Utf8: "append"
#38: Utf8: "(Ljava/lang/String;)Ljava/lang/StringBuilder;"
#39: Utf8: "(I)Ljava/lang/StringBuilder;"
#40: Utf8: "toString"
#41: Utf8: "()Ljava/lang/String;"
#42: Utf8: "java/io/PrintStream"
#43: Utf8: "println"
#44: Utf8: "(Ljava/lang/String;)V"
Access flags: 0x21 public super
This class: 11=test, super: 12=java.lang.Object
Interfaces (count: 0):
Fields (count: 0):
Methods (count: 2):
Method name:"<init>" public Signature: 14=()void
Attribute "Code", length:29, max_stack:1, max_locals:1, code_length:5
Attribute "LineNumberTable", length:6, count: 1
Method name:"main" public static Signature: 18=(java.lang.String[])void
Attribute "Code", length:74, max_stack:3, max_locals:3, code_length:34
Attribute "LineNumberTable", length:22, count: 5
Attributes (count: 1):
Attribute "SourceFile", length:2, #20="test.java"



만약 1.5로 컴파일하면, major_version은 49가 될 것이다.


아주 큰 장점은..  자바의 타겟 컴파일 이슈가 문제가 될 때, 바로 이 툴로 확인할 수 있을 것이다.

ClassFormatError, ClassNotFoundException 이런 이슈등에 해결될 수 있을 것이다.

  • 46 = Java 1.2
  • 47 = Java 1.3
  • 48 = Java 1.4
  • 49 = Java 5
  • 50 = Java 6
  • 51 = Java 7

-c 옵션을 주어서, method의 실제 동작되는 jvm assembly를 볼 수 있다.
$ gcj-dump -c test.java
Methods (count: 2):
Method name:"<init>" public Signature: 14=()void
Attribute "Code", length:29, max_stack:1, max_locals:1, code_length:5
  0: aload_0
  1: invokespecial #1=<Method java.lang.Object.<init> ()void>
  4: return
Attribute "LineNumberTable", length:6, count: 1
  line: 1 at pc: 0
Method name:"main" public static Signature: 18=(java.lang.String[])void
Attribute "Code", length:74, max_stack:3, max_locals:3, code_length:34
  0: iconst_0
  1: istore_1
  2: ldc #2=<String "temp">
  4: astore_2
  5: iinc 1 1
  8: getstatic #3=<Field java.lang.System.out java.io.PrintStream>
 11: new #4=<Class java.lang.StringBuilder>
 14: dup
 15: invokespecial #5=<Method java.lang.StringBuilder.<init> ()void>
 18: ldc #6=<String "a:">
 20: invokevirtual #7=<Method java.lang.StringBuilder.append (java.lang.String)java.lang.StringBuilder>
 23: iload_1
 24: invokevirtual #8=<Method java.lang.StringBuilder.append (int)java.lang.StringBuilder>
 27: invokevirtual #9=<Method java.lang.StringBuilder.toString ()java.lang.String>
 30: invokevirtual #10=<Method java.io.PrintStream.println (java.lang.String)void>
 33: return
Attribute "LineNumberTable", length:22, count: 5
  line: 3 at pc: 0
  line: 4 at pc: 2
  line: 5 at pc: 5
  line: 6 at pc: 8
  line: 7 at pc: 33


이것을 이용하면, 나중에 java 7에서 invoke 개선안에 대해서 어떻게 동작하는지 쉽게 볼 수 있을 것이다.


javap 결과도 보여줄 수 있다.
$ jcf-dump -javap test
Reading .class from ./test.class.
Magic number: 0xcafebabe, minor_version: 0, major_version: 50.
Access flags: 0x21 public super
This class: test, super: java.lang.Object
Interfaces (count: 0):
Fields (count: 0):
Methods (count: 2):
     public void "<init>"()
     public static void "main"(java.lang.String[])






개발하다보면, java5에서 java6로 넘어가는 과정에서 많은 고민이 있었다. 내년에도 이런 식으로 이슈가 있을 것이다. 개발환경은 java7인데, 운영환경은 java6로 했을때, jvm이 인식못하는 jvm assembly 나 타겟 이슈가 있을 때, 이 툴을 이용하면 개발자들이 자주 실수 하는 부분을 찾아낼 수 있을 것이다.

간단하게 하면 머 이런식이 될 것이다.

$ jcf-dump -javap test | grep 'major_' | awk '{if($7=="50.") print "jdk 1.6"; else if($7=="51.") print "jdk 1.7";}'
jdk 1.6





사실 굳이 jcf-dump로 확인할 필요가 없다. 리눅스의 file 명령어로 확인할 수 있다. ㅎㅎㅎ

$ file test.class
test.class: compiled Java class data, version 50.0


Posted by '김용환'
,

발표 자료 중 내 눈에 띄인 자료들만 공유한다.


1. Apache Traffic Server



Yahoo에서 캐쉬 서버로 활용하고 있으며, 

cpu core당 n개의 worker thread,

디스크당 m개의 thread, 

여러 쓰레드( 요청을 받을때, logging, admin)용을 위한 쓰레드 (최대 10개 미만)

으로 쓰레드 모델을 가지고 있어서 성능을 높였다고 발표했다.




2. Apache Http 2.4


2.4에서 Async IO를 지원하고 성능을 높였다고 한다.

그동안 apache http 서버는 async 기능이 없어서 nginx를 많이 활용하려고 했던 분위기였으며, 이 버전이 릴리즈되면 상황이 바뀔 수도 있겠다하는 생각이 들었다.  

그 외, bandwidth를 조절, timeout을 조절, 로깅,  if 지시자,  io 버퍼 조절를 지원하고, http 서버에 Lua 언어도 지원할지 모른다고 한다.

 특이사항으로는 http 서버가 proxy서버로 쓰이기 때문에 cloud 환경에서도 쓸 수 있도록 다양한 기능을 내어 놓는다고 한다. http, https, connect, ftp, ajp, cgi, load balancing, clustering, failover 등 기존의 좋은 장점과 클라우드의 특징까지 넣을 예정이라고 한다 . (제가 봤을 때는 그냥 기존의 proxy balancer에 환경설정만 더 추가한 것 같은데.. 잘 포장하려고 한것 같긴 해요)

좀더 특징적인 것은 어드민기능(모니터링 또는 파라미터 조정)이 가능하다.


 

이자료에 가장 흥미있는 것은 nginx와의 성능 비교를 제시했다는 것이다.  특이한 설정없는 상황에서 했을때..

거의 비슷한 성능이 나온 것 같다.




나름 결론으로 아래와 같은 얘기를 썼다.

- event, polling, fork/spawn 방식은 오버헤드가 있지만, 기대치보다 좋은 성능을 가질 것이다.

- concurrency 관점에서는 apache http 2.4의 event & worker 는 nginx와 비슷한 성능이다.

- transaction speed 관점에서는 apache http 2.4의 perfork 방식이 좋다.

 
3. Tomcat 얘기


tomcat native with comet 이야기
이외, servlet 3.0과 jsf 를 설명한 문서..




4. Hadoop Profiling
Hadoop profiling에 대한 노하우 공유



5. Apache Technology
Big data 처리에 관련된 모든 Apache project를 요약했다. 생소한 incubator project도 알게됨..

좋은 (Cool) 프로젝트에 대한 정보를 다룸





6. Cassandra 1.0 릴리즈

카산드라 1.0 특징
- Compression
- Read performance : maxtimestamp (많이 좋아졌음)
- LeveledCompactionStrategy (멀티쓰레딩, 16mb optional throttling, 5mb default data file)
- CQL 1.1
- Better Hinted Handoff Tracking

jni대신 jna 를 사용함. 메모리를 heap 영역이 아닌 native heap으로 바꿔서 heap gc가 자주 발생되지 않도록 함


7. HA for Hadoop NameNode

ebay 개발자가 쓴 것으로 상당히 재미있었음.. ^^
HA에 대한 고민과 디자인에 대한 내용이 있음.  자동 HA 대신 사람이 해주는 HA 솔루션도 소개해줌
Automatic-Hot HA은 현실적이었던 것 같음






8. Jmeter

Hudson을 이용해서 모듈이나 서비스에서 성능 테스트를 진행할 수 있다. 
핵심 모듈의 경우, 이 성능지표를 계속 측정함으로서, 얼마나 성능이 저하되지 않도록 하는 것이 중요하기 때문에. 필요한 것이다.


9. Rave 

위젯 엔진처럼 웹싸이트를 구축할 수 있는 툴같다. 인큐베이터 프로젝트이지만, 기대가 된다. 



10. Phonegap/Callback

내용은 없다. 그냥 폰갭에 대한 아주 심플한 ppt이다.


11. Scaling Hadoop

아래 항목에 대해서 Hadoop Scale에 대한 좋은 내용과 best practise 가 있다.
- Sequential Bottlenecks
- Load Imbalance
- Critical Paths
- Algorithmic Overheads
- Synchronization 
- Granularity/Communication Overheads


12. Lucene 4.0

lucene이 발전하는 모습이 좋다. 









 

Posted by '김용환'
,

 

TomcatJreMemoryLeakPreventionListener gcDaemonProtection true값이 디폴트이다. Tomcat GC Daemon을 하나 만들어서 sun.misc.GC.requestLatency(long) 메소드를 호출하게 된다. JreMemoryLeakPreventionListener 소스에서는 1시간단위로 해당 메소드를 호출하도록 되어 있다.

따라서, server.xml에 아래 내용을 추가하여 Full GC가 일어나지 않도록 수정되어야 한다.

<Listener className="org.apache.catalina.core.JreMemoryLeakPreventionListener"

gcDaemonProtection="false"/>

Tomcat 5에서는 아래 내용이 적용되지 않으며, Tomcat 6이상에서만 적용된다.

http://tomcat.apache.org/tomcat-6.0-doc/config/listeners.html

'Web service' 카테고리의 다른 글

Webwork(Strust2), OGNL, Sitemesh  (0) 2011.12.13
이클립스 - PHP-Java 개발환경 구축  (0) 2011.12.07
리눅스(ubuntu)에서 XE 1.5.0_4 beta 설치  (0) 2011.10.11
Nginx  (9) 2011.09.27
Apache Killer 와 Apache Http 패치 (DOS) 2.20  (0) 2011.09.01
Posted by '김용환'
,