윈도우 이클립스에서 안드로이드 어플을 개발할 때 API 보는 것 대신 소스를 보려면, 두가지 중 하나를 하면 된다.
1. 소스를 다운받기
tortoiseGit 프로그램을 이용해서 아래 주소에 git 파일을 가지고 clone한다.
https://android.googlesource.com/platform/frameworks/base.git
2. 자바 소스 zip 파일 다운 받기
https://github.com/android/platform_frameworks_base/tags 디렉토리에 접근해서 버전에 맞게 소스를 다운받으면 된다.
예전에는 소스를 다운받는 구조로 했었는데.. 별로 안좋은 것 같다.
웹 브라우져에서 https://github.com/android/platform_frameworks_base/tags 에 접속한다.
나는 안드로이드 2.3.3 어플을 개발중이므로, android_2.3.3_r1을 다운받는다.
안드로이드 소스 연동 이클립스에서 SurfaceView 클래스의 소스를 보려고 했을 때, 아래와 같은 화면이 나타난다.
여기서 Attach Source의 External File을 선택후, 다운받은 zip 파일을 연결한다. (사진에 그림을 잘 못 그렸음..)
아래와 같이 안드로드이 자바 소스를 확인할 수 있다.
Posted by 김용환 '김용환'
LG U+ 갤택에 아이스크림을 올릴기 위해서, 이것저것 해보고 있다.
네이버 갤탭 사용자 카페에서 SK와 와탭은 되는데, LG U+ 제품은 잘 안된다고 한다.
안되도 공부하는 셈치고 해보려고 한다.
xda 개발자가 쓴 내용을 바탕으로 갤택 7인치 아이스크림 버전을 다운받고 컴파일을 완료했다.
http://forum.xda-developers.com/showthread.php?t=1385153
1. 툴 설치
소스 컴파일을 위한 준비를 한다.
http://source.android.com/source/initializing.html
아래 참조 : http://knight76.tistory.com/entry/안드로이드-소스-컴파일-ubuntu-1104-android-gingerbread
2. repo 다운로드
$ curl https://dl-ssl.google.com/dl/googlesource/git-repo/repo > repo
$ chmod a+x repo
3. 안드로이드 소스 다운로드
$ mkdir android4
$ cd android4
$ repo init -u https://android.googlesource.com/platform/manifest -b android-4.0.1_r1
$ repo sync
4. xda의 cm9 소스 다운로드
mkdir cm9
cd cm9
repo init -u git://github.com/sgt7/android.git -b ics
repo sync
5. 컴파일 준비 및 컴파일
$ . build/envsetup.sh
including device/moto/stingray/vendorsetup.sh
including device/moto/wingray/vendorsetup.sh
including device/samsung/galaxytab/vendorsetup.sh
including device/samsung/maguro/vendorsetup.sh
including device/samsung/toro/vendorsetup.sh
including device/ti/panda/vendorsetup.sh
including vendor/cm/vendorsetup.sh
including sdk/bash_completion/adb.bash
$ lunch cm_galaxytab-userdebug
============================================
PLATFORM_VERSION_CODENAME=REL
PLATFORM_VERSION=4.0.3
TARGET_PRODUCT=cm_galaxytab
TARGET_BUILD_VARIANT=userdebug
TARGET_BUILD_TYPE=release
TARGET_BUILD_APPS=
TARGET_ARCH=arm
TARGET_ARCH_VARIANT=armv7-a-neon
HOST_ARCH=x86
HOST_OS=linux
HOST_BUILD_TYPE=release
BUILD_ID=MR1
============================================
$ make bacon
6. 컴파일 결과 확인
타겟 보드향이기 때문에 out/target 에 디렉토리가 있을 것이다.
android4/out/target/product/galaxytab $ ls -al
total 22428
drwxr-xr-x 8 kimyonghwan kimyonghwan 4096 2012-01-09 20:43 .
drwxr-xr-x 3 kimyonghwan kimyonghwan 4096 2012-01-09 20:36 ..
-rw-r--r-- 1 kimyonghwan kimyonghwan 8563349 2012-01-09 20:43 boot.img
-rw-r--r-- 1 kimyonghwan kimyonghwan 18719 2012-01-09 20:36 clean_steps.mk
drwxr-xr-x 15 kimyonghwan kimyonghwan 4096 2012-01-09 22:26 obj
-rw-r--r-- 1 kimyonghwan kimyonghwan 571 2012-01-09 20:36 previous_build_config.mk
-rw-r--r-- 1 kimyonghwan kimyonghwan 590256 2012-01-09 20:42 ramdisk.img
-rw-r--r-- 1 kimyonghwan kimyonghwan 3330560 2012-01-09 20:42 ramdisk-recovery.cpio
-rw-r--r-- 1 kimyonghwan kimyonghwan 1850517 2012-01-09 20:42 ramdisk-recovery.img
drwxr-xr-x 3 kimyonghwan kimyonghwan 4096 2012-01-09 20:42 recovery
-rw-r--r-- 1 kimyonghwan kimyonghwan 8563349 2012-01-09 20:43 recovery.img
drwxr-xr-x 9 kimyonghwan kimyonghwan 4096 2012-01-09 20:42 root
drwxr-xr-x 5 kimyonghwan kimyonghwan 4096 2012-01-09 20:43 symbols
drwxr-xr-x 9 kimyonghwan kimyonghwan 4096 2012-01-09 23:10 system
drwxr-xr-x 2 kimyonghwan kimyonghwan 4096 2012-01-09 20:43 utilities
boot.img, root, system fs 은 나왔는데, zImage 파일이 없다. 자동으로 나올줄 알았는데..
cm9 공부좀 해야겠는데...
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 김용환 '김용환'
댓글을 달아 주세요
덕분에 리눅스 설치 없이 쉽게 받았습니다.
감사합니다.
정말 감사합니다. 왠만한건 전부 소스를 볼수있는데 xml 코드는 볼수가 없네요..
어떻게 방법이 없을까요?