understanding android - Android Software/Hacking General [Developers Only]
http://forum.xda-developers.com/showthread.php?t=2514846
I'm fresh in xda, so I can't post in "Android Development and Hacking > Android Software and Hacking General [Developers Only] ". Instead, I have to post on gerneral forum. the location of previous post is http://forum.xda-developers.com/showthread.php?t=2514846.
We haven't talked with any press for publishing yet. So if any press is interested in publishing this book, please contact me. As you all know, writing is a tough job, especially when the book is regarding such a complicated android os system, so cheers, encouragement and funding are welcomed badly. Funding would help us not worry about making a living and dedicate to the writing or even hire some people to accelerate the progress. For funding, please visit:
mod edit
Please Rate the thread 5 Stars and click the Thanks Button! (any of my posts will do!)
JAVA interface for HAL module
sorry, the title should be JNI interface for HAL module
1. new com_android_server_HelloService.cpp
[email protected]:~/Android$ cd frameworks/base/services/jni
[email protected]:~/Android/frameworks/base/services/jni$ vi com_android_server_HelloService.cpp
#define LOG_TAG "HelloService"
#include "jni.h"
#include "JNIHelp.h"
#include "android_runtime/AndroidRuntime.h"
#include <utils/misc.h>
#include <utils/Log.h>
#include <hardware/hardware.h>
#include <hardware/hello.h>
#include <stdio.h>
namespace android
{
/*在硬件抽象层中定义的硬件访问结构体,参考<hardware/hello.h>*/
struct hello_device_t* hello_device = NULL;
/*通过硬件抽象层定义的硬件访问接口设置硬件寄存器val的值*/
static void hello_setVal(JNIEnv* env, jobject clazz, jint value) {
int val = value;
LOGI("Hello JNI: set value %d to device.", val);
if(!hello_device) {
LOGI("Hello JNI: device is not open.");
return;
}
hello_device->set_val(hello_device, val);
}
/*通过硬件抽象层定义的硬件访问接口读取硬件寄存器val的值*/
static jint hello_getVal(JNIEnv* env, jobject clazz) {
int val = 0;
if(!hello_device) {
LOGI("Hello JNI: device is not open.");
return val;
}
hello_device->get_val(hello_device, &val);
LOGI("Hello JNI: get value %d from device.", val);
return val;
}
/*通过硬件抽象层定义的硬件模块打开接口打开硬件设备*/
static inline int hello_device_open(const hw_module_t* module, struct hello_device_t** device) {
return module->methods->open(module, HELLO_HARDWARE_MODULE_ID, (struct hw_device_t**)device);
}
/*通过硬件模块ID来加载指定的硬件抽象层模块并打开硬件*/
static jboolean hello_init(JNIEnv* env, jclass clazz) {
hello_module_t* module;
LOGI("Hello JNI: initializing......");
if(hw_get_module(HELLO_HARDWARE_MODULE_ID, (const struct hw_module_t**)&module) == 0) {
LOGI("Hello JNI: hello Stub found.");
if(hello_device_open(&(module->common), &hello_device) == 0) {
LOGI("Hello JNI: hello device is open.");
return 0;
}
LOGE("Hello JNI: failed to open hello device.");
return -1;
}
LOGE("Hello JNI: failed to get hello stub module.");
return -1;
}
/*JNI方法表*/
static const JNINativeMethod method_table[] = {
{"init_native", "()Z", (void*)hello_init},
{"setVal_native", "(I)V", (void*)hello_setVal},
{"getVal_native", "()I", (void*)hello_getVal},
};
/*注册JNI方法*/
int register_android_server_HelloService(JNIEnv *env) {
return jniRegisterNativeMethods(env, "com/android/server/HelloService", method_table, NELEM(method_table));
}
};
2. modify onload.cpp in frameworks/base/services/jni
add register_android_server_HelloService to namespace android
namespace android {
..............................................................................................
int register_android_server_HelloService(JNIEnv *env);
};
在JNI_onLoad增加register_android_server_HelloService函数调用:
extern "C" jint JNI_onLoad(JavaVM* vm, void* reserved)
{
.................................................................................................
register_android_server_HelloService(env);
.................................................................................................
}
3. modify Android.mk in frameworks/base/services/jni, add com_android_server_HelloService.cpp
LOCAL_SRC_FILES:= \
com_android_server_AlarmManagerService.cpp \
com_android_server_BatteryService.cpp \
com_android_server_InputManager.cpp \
com_android_server_LightsService.cpp \
com_android_server_PowerManagerService.cpp \
com_android_server_SystemServer.cpp \
com_android_server_UsbService.cpp \
com_android_server_VibratorService.cpp \
com_android_server_location_GpsLocationProvider.cpp \
com_android_server_HelloService.cpp /
onload.cpp
4. build and repack system.img
[email protected]:~/Android$ mmm frameworks/base/services/jni
[email protected]:~/Android$ make snod
service to the Android hardware
1. defite the service interface to hardware
[email protected]:~/Android$ cd frameworks/base/core/java/android/os
[email protected]:~/Android/frameworks/base/core/java/android/os$ vi IHelloService.aidl
package android.os;
interface IHelloService {
void setVal(int val);
int getVal();
}
2. modify Android.mk in frameworks/base, add IHelloService.aidl to LOCAL_SRC_FILES
## READ ME: ########################################################
##
## When updating this list of aidl files, consider if that aidl is
## part of the SDK API. If it is, also add it to the list below that
## is preprocessed and distributed with the SDK. This list should
## not contain any aidl files for parcelables, but the one below should
## if you intend for 3rd parties to be able to send those objects
## across process boundaries.
##
## READ ME: ########################################################
LOCAL_SRC_FILES += /
....................................................................
core/java/android/os/IVibratorService.aidl /
core/java/android/os/IHelloService.aidl /
core/java/android/service/urlrenderer/IUrlRendererService.aidl /
.....................................................................
3. build
[email protected]:~/Android$ mmm frameworks/base
4. new HelloService.java in frameworks/base/services/java/com/android/server
package com.android.server;
import android.content.Context;
import android.os.IHelloService;
import android.util.Slog;
public class HelloService extends IHelloService.Stub {
private static final String TAG = "HelloService";
HelloService() {
init_native();
}
public void setVal(int val) {
setVal_native(val);
}
public int getVal() {
return getVal_native();
}
private static native boolean init_native();
private static native void setVal_native(int val);
private static native int getVal_native();
};
5. modify SystemServer.java in frameworks/base/services/java/com/android/server, change ServerThread::run
@override
public void run() {
....................................................................................
try {
Slog.i(TAG, "DiskStats Service");
ServiceManager.addService("diskstats", new DiskStatsService(context));
} catch (Throwable e) {
Slog.e(TAG, "Failure starting DiskStats Service", e);
}
try {
Slog.i(TAG, "Hello Service");
ServiceManager.addService("hello", new HelloService());
} catch (Throwable e) {
Slog.e(TAG, "Failure starting Hello Service", e);
}
......................................................................................
}
6. build HelloService and repack system.img
[email protected]:~/Android$ mmm frameworks/base/services/java
[email protected]:~/Android$ make snod
Android test application on the service to hardware
1. Hello.java
package shy.luo.hello;
import shy.luo.hello.R;
import android.app.Activity;
import android.os.ServiceManager;
import android.os.Bundle;
import android.os.IHelloService;
import android.os.RemoteException;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
public class Hello extends Activity implements OnClickListener {
private final static String LOG_TAG = "shy.luo.renju.Hello";
private IHelloService helloService = null;
private EditText valueText = null;
private Button readButton = null;
private Button writeButton = null;
private Button clearButton = null;
/** Called when the activity is first created. */
@override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
helloService = IHelloService.Stub.asInterface(
ServiceManager.getService("hello"));
valueText = (EditText)findViewById(R.id.edit_value);
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(LOG_TAG, "Hello Activity Created");
}
@override
public void onClick(View v) {
if(v.equals(readButton)) {
try {
int val = helloService.getVal();
String text = String.valueOf(val);
valueText.setText(text);
} catch (RemoteException e) {
Log.e(LOG_TAG, "Remote Exception while reading value from device.");
}
}
else if(v.equals(writeButton)) {
try {
String text = valueText.getText().toString();
int val = Integer.parseInt(text);
helloService.setVal(val);
} catch (RemoteException e) {
Log.e(LOG_TAG, "Remote Exception while writing value to device.");
}
}
else if(v.equals(clearButton)) {
String text = "";
valueText.setText(text);
}
}
}
res/layout/main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
androidrientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
androidrientation="vertical"
android:gravity="center">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/value">
</TextView>
<EditText
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:id="@+id/edit_value"
android:hint="@string/hint">
</EditText>
</LinearLayout>
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
androidrientation="horizontal"
android:gravity="center">
<Button
android:id="@+id/button_read"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/read">
</Button>
<Button
android:id="@+id/button_write"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/write">
</Button>
<Button
android:id="@+id/button_clear"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/clear">
</Button>
</LinearLayout>
</LinearLayout>
res/values/strings.xml:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="app_name">Hello</string>
<string name="value">Value</string>
<string name="hint">Please input a value...</string>
<string name="read">Read</string>
<string name="write">Write</string>
<string name="clear">Clear</string>
</resources>
AndroidManifest.xml:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="shy.luo.hello"
android:versionCode="1"
android:versionName="1.0">
<application android:icon="@drawable/icon" android:label="@string/app_name">
<activity android:name=".Hello"
android:label="@string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
2. Android.mk
copy dir Hello to packages/experimental, add Android.mk:
[email protected]:~/Android/packages/experimental$ vi Android.mk
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE_TAGS := optional
LOCAL_SRC_FILES := $(call all-subdir-java-files)
LOCAL_PACKAGE_NAME := Hello
include $(BUILD_PACKAGE)
3. build hello and repack system.img
[email protected]:~/Android$ mmm packages/experimental/Hello
[email protected]:~/Android$ make snod
log in android
1. kernel log
<linux/kernel.h>
#define KERN_EMERG "<0>" /* system is unusable */
#define KERN_ALERT "<1>" /* action must be taken immediately */
#define KERN_CRIT "<2>" /* critical conditions */
#deinfe KERN_ERR "<3>" /* error conditions */
#deinfe KERN_WARNING "<4>" /* warning conditions */
#deinfe KERN_NOTICE "<5>" /* normal but significant condition */
#deinfe KERN_INFO "<6>" /* informational */
#deinfe KERN_DEBUG "<7>" /* debug-level messages */
printk(KERN_ALERT"This is the log printed by printk in linux kernel space.");
to read the log:
[email protected]:~/Android$ emulator &
[email protected]:~/Android$ adb shell
[email protected]:/ # cat /proc/kmsg
2. LOG for app
C/C++:
system/core/include/android/log.h
/*
* Android log priority values, in ascending priority order.
*/
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;
system/core/include/cutils/log.h
/*
* This is the local tag used for the following simplified
* logging macros. You can change this preprocessor definition
* before using the other macros to change the tag.
*/
#ifndef LOG_TAG
#define LOG_TAG NULL
#endif
/*
* Simplified macro to send a verbose log message using the current LOG_TAG.
*/
#ifndef LOGV
#if LOG_NDEBUG
#define LOGV(...) ((void)0)
#else
#define LOGV(...) ((void)LOG(LOG_VERBOSE, LOG_TAG, __VA_ARGS__))
#endif
#endif
/*
* Basic log message macro.
*
* Example:
* LOG(LOG_WARN, NULL, "Failed with error %d", errno);
*
* The second argument may be NULL or "" to indicate the "global" tag.
*/
#ifndef LOG
#define LOG(priority, tag, ...) \
LOG_PRI(ANDROID_##priority, tag, __VA_ARGS__)
#endif
/*
* Log macro that allows you to specify a number for priority.
*/
#ifndef LOG_PRI
#define LOG_PRI(priority, tag, ...) \
android_printLog(priority, tag, __VA_ARGS__)
#endif
/*
* ================================================================
*
* The stuff in the rest of this file should not be used directly.
*/
#define android_printLog(prio, tag, fmt...) \
__android_log_print(prio, tag, fmt)
to use:
#define LOG_TAG "MY LOG TAG"
#include <cutils/log.h>
LOGV("This is the log printed by LOGV in android user space.");
java:
frameworks/base/core/java/android/util/Log.java
................................................
public final class Log {
................................................
/**
* Priority constant for the println method; use Log.v.
*/
public static final int VERBOSE = 2;
/**
* Priority constant for the println method; use Log.d.
*/
public static final int DEBUG = 3;
/**
* Priority constant for the println method; use Log.i.
*/
public static final int INFO = 4;
/**
* Priority constant for the println method; use Log.w.
*/
public static final int WARN = 5;
/**
* Priority constant for the println method; use Log.e.
*/
public static final int ERROR = 6;
/**
* Priority constant for the println method.
*/
public static final int ASSERT = 7;
.....................................................
public static int v(String tag, String msg) {
return println_native(LOG_ID_MAIN, VERBOSE, tag, msg);
}
public static int v(String tag, String msg, Throwable tr) {
return println_native(LOG_ID_MAIN, VERBOSE, tag, msg + '\n' + getStackTraceString(tr));
}
public static int d(String tag, String msg) {
return println_native(LOG_ID_MAIN, DEBUG, tag, msg);
}
public static int d(String tag, String msg, Throwable tr) {
return println_native(LOG_ID_MAIN, DEBUG, tag, msg + '\n' + getStackTraceString(tr));
}
public static int i(String tag, String msg) {
return println_native(LOG_ID_MAIN, INFO, tag, msg);
}
public static int i(String tag, String msg, Throwable tr) {
return println_native(LOG_ID_MAIN, INFO, tag, msg + '\n' + getStackTraceString(tr));
}
public static int w(String tag, String msg) {
return println_native(LOG_ID_MAIN, WARN, tag, msg);
}
public static int w(String tag, String msg, Throwable tr) {
return println_native(LOG_ID_MAIN, WARN, tag, msg + '\n' + getStackTraceString(tr));
}
public static int w(String tag, Throwable tr) {
return println_native(LOG_ID_MAIN, WARN, tag, getStackTraceString(tr));
}
public static int e(String tag, String msg) {
return println_native(LOG_ID_MAIN, ERROR, tag, msg);
}
public static int e(String tag, String msg, Throwable tr) {
return println_native(LOG_ID_MAIN, ERROR, tag, msg + '\n' + getStackTraceString(tr));
}
..................................................................
/**@hide */ public static native int println_native(int bufID,
int priority, String tag, String msg);
}
to use:
private static final String LOG_TAG = "MY_LOG_TAG";
Log.i(LOG_TAG, "This is the log printed by Log.i in android user space.");
read log:
[email protected]:~/Android$ emulator &
[email protected]:~/Android$ adb shell
[email protected]:/ # logcat
standalone android emulator
1. download Android SDK
2. mkdir D:\AndroidEmulator
3. mkdir D:\AndroidEmulator\images
copy android-sdk-windows\platforms\android-7\images to this dir
4. mkdir D:\AndroidEmulator\skins
copy android-sdk-windows\platforms\android-7\skins to this dir.
4. start emulator
D:\AndroidEmulator>start /b emulator.exe -sysdir d:\AndroidEmulator -system images\system.img -data images\userdata.img -ramdisk images\ramdisk.img -kernel images\kernel-qemu -skindir d:\AndroidEmulator\skins -skin HVGA
Logger driver
kernel/common/drivers/staging/android/logger.h
kernel/common/drivers/staging/android/logger.c
1. data structure
logger.h:
#ifndef _LINUX_LOGGER_H
#define _LINUX_LOGGER_H
#include <linux/types.h>
#include <linux/ioctl.h>
struct logger_entry {
__u16 len; /* length of the payload */
__u16 __pad; /* no matter what, we get 2 bytes of padding */
__s32 pid; /* generating process's pid */
__s32 tid; /* generating process's tid */
__s32 sec; /* seconds since Epoch */
__s32 nsec; /* nanoseconds */
char msg[0]; /* the entry's payload */
};
#define LOGGER_LOG_RADIO "log_radio" /* radio-related messages */
#define LOGGER_LOG_EVENTS "log_events" /* system/hardware events */
#define LOGGER_LOG_MAIN "log_main" /* everything else */
#define LOGGER_ENTRY_MAX_LEN (4*1024)
#define LOGGER_ENTRY_MAX_PAYLOAD \
(LOGGER_ENTRY_MAX_LEN - sizeof(struct logger_entry))
#define __LOGGERIO 0xAE
#define LOGGER_GET_LOG_BUF_SIZE _IO(__LOGGERIO, 1) /* size of log */
#define LOGGER_GET_LOG_LEN _IO(__LOGGERIO, 2) /* used log len */
#define LOGGER_GET_NEXT_ENTRY_LEN _IO(__LOGGERIO, 3) /* next entry len */
#define LOGGER_FLUSH_LOG _IO(__LOGGERIO, 4) /* flush log */
#endif /* _LINUX_LOGGER_H */
logger.c:
/*
* struct logger_log - represents a specific log, such as 'main' or 'radio'
*
* This structure lives from module insertion until module removal, so it does
* not need additional reference counting. The structure is protected by the
* mutex 'mutex'.
*/
struct logger_log {
unsigned char * buffer; /* the ring buffer itself */
struct miscdevice misc; /* misc device representing the log */
wait_queue_head_t wq; /* wait queue for readers */
struct list_head readers; /* this log's readers */
struct mutex mutex; /* mutex protecting buffer */
size_t w_off; /* current write head offset */
size_t head; /* new readers start here */
size_t size; /* size of the log */
};
/*
* struct logger_reader - a logging device open for reading
*
* This object lives from open to release, so we don't need additional
* reference counting. The structure is protected by log->mutex.
*/
struct logger_reader {
struct logger_log * log; /* associated log */
struct list_head list; /* entry in logger_log's list */
size_t r_off; /* current read head offset */
};
/* logger_offset - returns index 'n' into the log via (optimized) modulus */
#define logger_offset ( & (log->size - 1))
2.initialization
/*
* Defines a log structure with name 'NAME' and a size of 'SIZE' bytes, which
* must be a power of two, greater than LOGGER_ENTRY_MAX_LEN, and less than
* LONG_MAX minus LOGGER_ENTRY_MAX_LEN.
*/
#define DEFINE_LOGGER_DEVICE(VAR, NAME, SIZE) \
static unsigned char _buf_ ## VAR[SIZE]; \
static struct logger_log VAR = { \
.buffer = _buf_ ## VAR, \
.misc = { \
.minor = MISC_DYNAMIC_MINOR, \
.name = NAME, \
.fops = &logger_fops, \
.parent = NULL, \
}, \
.wq = __WAIT_QUEUE_HEAD_INITIALIZER(VAR .wq), \
.readers = LIST_HEAD_INIT(VAR .readers), \
.mutex = __MUTEX_INITIALIZER(VAR .mutex), \
.w_off = 0, \
.head = 0, \
.size = SIZE, \
};
DEFINE_LOGGER_DEVICE(log_main, LOGGER_LOG_MAIN, 64*1024)
DEFINE_LOGGER_DEVICE(log_events, LOGGER_LOG_EVENTS, 256*1024)
DEFINE_LOGGER_DEVICE(log_radio, LOGGER_LOG_RADIO, 64*1024)
3. read the log
/*
* logger_read - our log's read() method
*
* Behavior:
*
* - O_NONBLOCK works
* - If there are no log entries to read, blocks until log is written to
* - Atomically reads exactly one log entry
*
* Optimal read size is LOGGER_ENTRY_MAX_LEN. Will set errno to EINVAL if read
* buffer is insufficient to hold next entry.
*/
static ssize_t logger_read(struct file *file, char __user *buf,
size_t count, loff_t *pos)
{
struct logger_reader *reader = file->private_data;
struct logger_log *log = reader->log;
ssize_t ret;
DEFINE_WAIT(wait);
start:
while (1) {
prepare_to_wait(&log->wq, &wait, TASK_INTERRUPTIBLE);
mutex_lock(&log->mutex);
ret = (log->w_off == reader->r_off);
mutex_unlock(&log->mutex);
if (!ret)
break;
if (file->f_flags & O_NONBLOCK) {
ret = -EAGAIN;
break;
}
if (signal_pending(current)) {
ret = -EINTR;
break;
}
schedule();
}
finish_wait(&log->wq, &wait);
if (ret)
return ret;
mutex_lock(&log->mutex);
/* is there still something to read or did we race? */
if (unlikely(log->w_off == reader->r_off)) {
mutex_unlock(&log->mutex);
goto start;
}
/* get the size of the next entry */
ret = get_entry_len(log, reader->r_off);
if (count < ret) {
ret = -EINVAL;
goto out;
}
/* get exactly one entry from the log */
ret = do_read_log_to_user(log, reader, buf, ret);
out:
mutex_unlock(&log->mutex);
return ret;
}
4. write the log
/*
* logger_aio_write - our write method, implementing support for write(),
* writev(), and aio_write(). Writes are our fast path, and we try to optimize
* them above all else.
*/
ssize_t logger_aio_write(struct kiocb *iocb, const struct iovec *iov,
unsigned long nr_segs, loff_t ppos)
{
struct logger_log *log = file_get_log(iocb->ki_filp);
size_t orig = log->w_off;
struct logger_entry header;
struct timespec now;
ssize_t ret = 0;
now = current_kernel_time();
header.pid = current->tgid;
header.tid = current->pid;
header.sec = now.tv_sec;
header.nsec = now.tv_nsec;
header.len = min_t(size_t, iocb->ki_left, LOGGER_ENTRY_MAX_PAYLOAD);
/* null writes succeed, return zero */
if (unlikely(!header.len))
return 0;
mutex_lock(&log->mutex);
/*
* Fix up any readers, pulling them forward to the first readable
* entry after (what will be) the new write offset. We do this now
* because if we partially fail, we can end up with clobbered log
* entries that encroach on readable buffer.
*/
fix_up_readers(log, sizeof(struct logger_entry) + header.len);
do_write_log(log, &header, sizeof(struct logger_entry));
while (nr_segs-- > 0) {
size_t len;
ssize_t nr;
/* figure out how much of this vector we can keep */
len = min_t(size_t, iov->iov_len, header.len - ret);
/* write out this segment's payload */
nr = do_write_log_from_user(log, iov->iov_base, len);
if (unlikely(nr < 0)) {
log->w_off = orig;
mutex_unlock(&log->mutex);
return nr;
}
iov++;
ret += nr;
}
mutex_unlock(&log->mutex);
/* wake up any blocked readers */
wake_up_interruptible(&log->wq);
return ret;
}
runtime library for the Logger driver
1. log interface for Java
................................................
public final class Log {
................................................
/**
* Priority constant for the println method; use Log.v.
*/
public static final int VERBOSE = 2;
/**
* Priority constant for the println method; use Log.d.
*/
public static final int DEBUG = 3;
/**
* Priority constant for the println method; use Log.i.
*/
public static final int INFO = 4;
/**
* Priority constant for the println method; use Log.w.
*/
public static final int WARN = 5;
/**
* Priority constant for the println method; use Log.e.
*/
public static final int ERROR = 6;
/**
* Priority constant for the println method.
*/
public static final int ASSERT = 7;
.....................................................
public static int v(String tag, String msg) {
return println_native(LOG_ID_MAIN, VERBOSE, tag, msg);
}
public static int v(String tag, String msg, Throwable tr) {
return println_native(LOG_ID_MAIN, VERBOSE, tag, msg + '\n' + getStackTraceString(tr));
}
public static int d(String tag, String msg) {
return println_native(LOG_ID_MAIN, DEBUG, tag, msg);
}
public static int d(String tag, String msg, Throwable tr) {
return println_native(LOG_ID_MAIN, DEBUG, tag, msg + '\n' + getStackTraceString(tr));
}
public static int i(String tag, String msg) {
return println_native(LOG_ID_MAIN, INFO, tag, msg);
}
public static int i(String tag, String msg, Throwable tr) {
return println_native(LOG_ID_MAIN, INFO, tag, msg + '\n' + getStackTraceString(tr));
}
public static int w(String tag, String msg) {
return println_native(LOG_ID_MAIN, WARN, tag, msg);
}
public static int w(String tag, String msg, Throwable tr) {
return println_native(LOG_ID_MAIN, WARN, tag, msg + '\n' + getStackTraceString(tr));
}
public static int w(String tag, Throwable tr) {
return println_native(LOG_ID_MAIN, WARN, tag, getStackTraceString(tr));
}
public static int e(String tag, String msg) {
return println_native(LOG_ID_MAIN, ERROR, tag, msg);
}
public static int e(String tag, String msg, Throwable tr) {
return println_native(LOG_ID_MAIN, ERROR, tag, msg + '\n' + getStackTraceString(tr));
}
..................................................................
/** @hide */ public static native int LOG_ID_MAIN = 0;
/** @hide */ public static native int LOG_ID_RADIO = 1;
/** @hide */ public static native int LOG_ID_EVENTS = 2;
/** @hide */ public static native int LOG_ID_SYSTEM = 3;
/** @hide */ public static native int println_native(int bufID,
int priority, String tag, String msg);
}
2. JNI for logger
frameworks/base/core/jni/android_util_Log.cpp
/* //device/libs/android_runtime/android_util_Log.cpp
**
** Copyright 2006, 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.
*/
#define LOG_NAMESPACE "log.tag."
#define LOG_TAG "Log_println"
#include <assert.h>
#include <cutils/properties.h>
#include <utils/Log.h>
#include <utils/String8.h>
#include "jni.h"
#include "utils/misc.h"
#include "android_runtime/AndroidRuntime.h"
#define MIN(a,b) ((a<b)?a:b)
namespace android {
struct levels_t {
jint verbose;
jint debug;
jint info;
jint warn;
jint error;
jint assert;
};
static levels_t levels;
static int toLevel(const char* value)
{
switch (value[0]) {
case 'V': return levels.verbose;
case 'D': return levels.debug;
case 'I': return levels.info;
case 'W': return levels.warn;
case 'E': return levels.error;
case 'A': return levels.assert;
case 'S': return -1; // SUPPRESS
}
return levels.info;
}
static jboolean android_util_Log_isLoggable(JNIEnv* env, jobject clazz, jstring tag, jint level)
{
#ifndef HAVE_ANDROID_OS
return false;
#else /* HAVE_ANDROID_OS */
int len;
char key[PROPERTY_KEY_MAX];
char buf[PROPERTY_VALUE_MAX];
if (tag == NULL) {
return false;
}
jboolean result = false;
const char* chars = env->GetStringUTFChars(tag, NULL);
if ((strlen(chars)+sizeof(LOG_NAMESPACE)) > PROPERTY_KEY_MAX) {
jclass clazz = env->FindClass("java/lang/IllegalArgumentException");
char buf2[200];
snprintf(buf2, sizeof(buf2), "Log tag \"%s\" exceeds limit of %d characters\n",
chars, PROPERTY_KEY_MAX - sizeof(LOG_NAMESPACE));
// release the chars!
env->ReleaseStringUTFChars(tag, chars);
env->ThrowNew(clazz, buf2);
return false;
} else {
strncpy(key, LOG_NAMESPACE, sizeof(LOG_NAMESPACE)-1);
strcpy(key + sizeof(LOG_NAMESPACE) - 1, chars);
}
env->ReleaseStringUTFChars(tag, chars);
len = property_get(key, buf, "");
int logLevel = toLevel(buf);
return (logLevel >= 0 && level >= logLevel) ? true : false;
#endif /* HAVE_ANDROID_OS */
}
/*
* In class android.util.Log:
* public static native int println_native(int buffer, int priority, String tag, String msg)
*/
static jint android_util_Log_println_native(JNIEnv* env, jobject clazz,
jint bufID, jint priority, jstring tagObj, jstring msgObj)
{
const char* tag = NULL;
const char* msg = NULL;
if (msgObj == NULL) {
jclass npeClazz;
npeClazz = env->FindClass("java/lang/NullPointerException");
assert(npeClazz != NULL);
env->ThrowNew(npeClazz, "println needs a message");
return -1;
}
if (bufID < 0 || bufID >= LOG_ID_MAX) {
jclass npeClazz;
npeClazz = env->FindClass("java/lang/NullPointerException");
assert(npeClazz != NULL);
env->ThrowNew(npeClazz, "bad bufID");
return -1;
}
if (tagObj != NULL)
tag = env->GetStringUTFChars(tagObj, NULL);
msg = env->GetStringUTFChars(msgObj, NULL);
int res = __android_log_buf_write(bufID, (android_LogPriority)priority, tag, msg);
if (tag != NULL)
env->ReleaseStringUTFChars(tagObj, tag);
env->ReleaseStringUTFChars(msgObj, msg);
return res;
}
/*
* JNI registration.
*/
static JNINativeMethod gMethods[] = {
/* name, signature, funcPtr */
{ "isLoggable", "(Ljava/lang/String;I)Z", (void*) android_util_Log_isLoggable },
{ "println_native", "(IILjava/lang/String;Ljava/lang/StringI", (void*) android_util_Log_println_native },
};
int register_android_util_Log(JNIEnv* env)
{
jclass clazz = env->FindClass("android/util/Log");
if (clazz == NULL) {
LOGE("Can't find android/util/Log");
return -1;
}
levels.verbose = env->GetStaticIntField(clazz, env->GetStaticFieldID(clazz, "VERBOSE", "I"));
levels.debug = env->GetStaticIntField(clazz, env->GetStaticFieldID(clazz, "DEBUG", "I"));
levels.info = env->GetStaticIntField(clazz, env->GetStaticFieldID(clazz, "INFO", "I"));
levels.warn = env->GetStaticIntField(clazz, env->GetStaticFieldID(clazz, "WARN", "I"));
levels.error = env->GetStaticIntField(clazz, env->GetStaticFieldID(clazz, "ERROR", "I"));
levels.assert = env->GetStaticIntField(clazz, env->GetStaticFieldID(clazz, "ASSERT", "I"));
return AndroidRuntime::registerNativeMethods(env, "android/util/Log", gMethods, NELEM(gMethods));
}
}; // namespace android
3. runtime library liblog
int __android_log_buf_write(int bufID, int prio, const char *tag, const char *msg)
{
struct iovec vec[3];
if (!tag)
tag = "";
/* XXX: This needs to go! */
if (!strcmp(tag, "HTC_RIL") ||
!strncmp(tag, "RIL", 3) || /* Any log tag with "RIL" as the prefix */
!strcmp(tag, "AT") ||
!strcmp(tag, "GSM") ||
!strcmp(tag, "STK") ||
!strcmp(tag, "CDMA") ||
!strcmp(tag, "PHONE") ||
!strcmp(tag, "SMS"))
bufID = LOG_ID_RADIO;
vec[0].iov_base = (unsigned char *) &prio;
vec[0].iov_len = 1;
vec[1].iov_base = (void *) tag;
vec[1].iov_len = strlen(tag) + 1;
vec[2].iov_base = (void *) msg;
vec[2].iov_len = strlen(msg) + 1;
return write_to_log(bufID, vec, 3);
}
static int __write_to_log_init(log_id_t, struct iovec *vec, size_t nr);
static int (*write_to_log)(log_id_t, struct iovec *vec, size_t nr) = __write_to_log_init;
static int __write_to_log_init(log_id_t log_id, struct iovec *vec, size_t nr)
{
#ifdef HAVE_PTHREADS
pthread_mutex_lock(&log_init_lock);
#endif
if (write_to_log == __write_to_log_init) {
log_fds[LOG_ID_MAIN] = log_open("/dev/"LOGGER_LOG_MAIN, O_WRONLY);
log_fds[LOG_ID_RADIO] = log_open("/dev/"LOGGER_LOG_RADIO, O_WRONLY);
log_fds[LOG_ID_EVENTS] = log_open("/dev/"LOGGER_LOG_EVENTS, O_WRONLY);
log_fds[LOG_ID_SYSTEM] = log_open("/dev/"LOGGER_LOG_SYSTEM, O_WRONLY);
write_to_log = __write_to_log_kernel;
if (log_fds[LOG_ID_MAIN] < 0 || log_fds[LOG_ID_RADIO] < 0 ||
log_fds[LOG_ID_EVENTS] < 0) {
log_close(log_fds[LOG_ID_MAIN]);
log_close(log_fds[LOG_ID_RADIO]);
log_close(log_fds[LOG_ID_EVENTS]);
log_fds[LOG_ID_MAIN] = -1;
log_fds[LOG_ID_RADIO] = -1;
log_fds[LOG_ID_EVENTS] = -1;
write_to_log = __write_to_log_null;
}
if (log_fds[LOG_ID_SYSTEM] < 0) {
log_fds[LOG_ID_SYSTEM] = log_fds[LOG_ID_MAIN];
}
}
#ifdef HAVE_PTHREADS
pthread_mutex_unlock(&log_init_lock);
#endif
return write_to_log(log_id, vec, nr);
}
...
Logcat tool
system/core/logcat
1. data structure
struct queued_entry_t {
union {
unsigned char buf[LOGGER_ENTRY_MAX_LEN + 1] __attribute__((aligned(4)));
struct logger_entry entry __attribute__((aligned(4)));
};
queued_entry_t* next;
queued_entry_t() {
next = NULL;
}
};
struct log_device_t {
char* device;
bool binary;
int fd;
bool printed;
char label;
queued_entry_t* queue;
log_device_t* next;
log_device_t(char* d, bool b, char l) {
device = d;
binary = b;
label = l;
queue = NULL;
next = NULL;
printed = false;
}
void enqueue(queued_entry_t* entry) {
if (this->queue == NULL) {
this->queue = entry;
} else {
queued_entry_t** e = &this->queue;
while (*e && cmp(entry, *e) >= 0) {
e = &((*e)->next);
}
entry->next = *e;
*e = entry;
}
}
};
2. initialization
static void setupOutput()
{
if (g_outputFileName == NULL) {
g_outFD = STDOUT_FILENO;
} else {
struct stat statbuf;
g_outFD = openLogFile (g_outputFileName);
if (g_outFD < 0) {
perror ("couldn't open output file");
exit(-1);
}
fstat(g_outFD, &statbuf);
g_outByteCount = statbuf.st_size;
}
}
dev = devices;
while (dev) {
dev->fd = open(dev->device, mode);
if (dev->fd < 0) {
fprintf(stderr, "Unable to open log device '%s': %s\n",
dev->device, strerror(errno));
exit(EXIT_FAILURE);
}
if (clearLog) {
int ret;
ret = android::clearLog(dev->fd);
if (ret) {
perror("ioctl");
exit(EXIT_FAILURE);
}
}
if (getLogSize) {
int size, readable;
size = android::getLogSize(dev->fd);
if (size < 0) {
perror("ioctl");
exit(EXIT_FAILURE);
}
readable = android::getLogReadableSize(dev->fd);
if (readable < 0) {
perror("ioctl");
exit(EXIT_FAILURE);
}
printf("%s: ring buffer is %dKb (%dKb consumed), "
"max entry is %db, max payload is %db\n", dev->device,
size / 1024, readable / 1024,
(int) LOGGER_ENTRY_MAX_LEN, (int) LOGGER_ENTRY_MAX_PAYLOAD);
}
dev = dev->next;
}
3. read the log
static void readLogLines(log_device_t* devices)
{
log_device_t* dev;
int max = 0;
int ret;
int queued_lines = 0;
bool sleep = true;
int result;
fd_set readset;
for (dev=devices; dev; dev = dev->next) {
if (dev->fd > max) {
max = dev->fd;
}
}
while (1) {
do {
timeval timeout = { 0, 5000 /* 5ms */ }; // If we oversleep it's ok, i.e. ignore EINTR.
FD_ZERO(&readset);
for (dev=devices; dev; dev = dev->next) {
FD_SET(dev->fd, &readset);
}
result = select(max + 1, &readset, NULL, NULL, sleep ? NULL : &timeout);
} while (result == -1 && errno == EINTR);
if (result >= 0) {
for (dev=devices; dev; dev = dev->next) {
if (FD_ISSET(dev->fd, &readset)) {
queued_entry_t* entry = new queued_entry_t();
/* NOTE: driver guarantees we read exactly one full entry */
ret = read(dev->fd, entry->buf, LOGGER_ENTRY_MAX_LEN);
if (ret < 0) {
if (errno == EINTR) {
delete entry;
goto next;
}
if (errno == EAGAIN) {
delete entry;
break;
}
perror("logcat read");
exit(EXIT_FAILURE);
}
else if (!ret) {
fprintf(stderr, "read: Unexpected EOF!\n");
exit(EXIT_FAILURE);
}
entry->entry.msg[entry->entry.len] = '\0';
dev->enqueue(entry);
++queued_lines;
}
}
if (result == 0) {
// we did our short timeout trick and there's nothing new
// print everything we have and wait for more data
sleep = true;
while (true) {
chooseFirst(devices, &dev);
if (dev == NULL) {
break;
}
if (g_tail_lines == 0 || queued_lines <= g_tail_lines) {
printNextEntry(dev);
} else {
skipNextEntry(dev);
}
--queued_lines;
}
// the caller requested to just dump the log and exit
if (g_nonblock) {
exit(0);
}
} else {
// print all that aren't the last in their list
sleep = false;
while (g_tail_lines == 0 || queued_lines > g_tail_lines) {
chooseFirst(devices, &dev);
if (dev == NULL || dev->queue->next == NULL) {
break;
}
if (g_tail_lines == 0) {
printNextEntry(dev);
} else {
skipNextEntry(dev);
}
--queued_lines;
}
}
}
next:
;
}
}
4. output the log
static void printNextEntry(log_device_t* dev) {
maybePrintStart(dev);
if (g_printBinary) {
printBinary(&dev->queue->entry);
} else {
processBuffer(dev, &dev->queue->entry);
}
skipNextEntry(dev);
}
void printBinary(struct logger_entry *buf)
{
size_t size = sizeof(logger_entry) + buf->len;
int ret;
do {
ret = write(g_outFD, buf, size);
} while (ret < 0 && errno == EINTR);
}
...
Binder driver
{
"lightbox_close": "Close",
"lightbox_next": "Next",
"lightbox_previous": "Previous",
"lightbox_error": "The requested content cannot be loaded. Please try again later.",
"lightbox_start_slideshow": "Start slideshow",
"lightbox_stop_slideshow": "Stop slideshow",
"lightbox_full_screen": "Full screen",
"lightbox_thumbnails": "Thumbnails",
"lightbox_download": "Download",
"lightbox_share": "Share",
"lightbox_zoom": "Zoom",
"lightbox_new_window": "New window",
"lightbox_toggle_sidebar": "Toggle sidebar"
}
start of Service Manager
frameworks/base/cmds/servicemanager
service_manager.c
int main(int argc, char **argv)
{
struct binder_state *bs;
void *svcmgr = BINDER_SERVICE_MANAGER;
bs = binder_open(128*1024);
if (binder_become_context_manager(bs)) {
LOGE("cannot become context manager (%s)\n", strerror(errno));
return -1;
}
svcmgr_handle = svcmgr;
binder_loop(bs, svcmgr_handler);
return 0;
}
frameworks/base/cmds/servicemanager/binder.c
struct binder_state
{
int fd;
void *mapped;
unsigned mapsize;
};
frameworks/base/cmds/servicemanager/binder.h
/* the one magic object */
#define BINDER_SERVICE_MANAGER ((void*) 0)
frameworks/base/cmds/servicemanager/binder.c
struct binder_state *binder_open(unsigned mapsize)
{
struct binder_state *bs;
bs = malloc(sizeof(*bs));
if (!bs) {
errno = ENOMEM;
return 0;
}
bs->fd = open("/dev/binder", O_RDWR);
if (bs->fd < 0) {
fprintf(stderr,"binder: cannot open device (%s)\n",
strerror(errno));
goto fail_open;
}
bs->mapsize = mapsize;
bs->mapped = mmap(NULL, mapsize, PROT_READ, MAP_PRIVATE, bs->fd, 0);
if (bs->mapped == MAP_FAILED) {
fprintf(stderr,"binder: cannot map device (%s)\n",
strerror(errno));
goto fail_map;
}
/* TODO: check version */
return bs;
fail_map:
close(bs->fd);
fail_open:
free(bs);
return 0;
}
kernel/common/drivers/staging/android
binder.c
static struct file_operations binder_fops = {
.owner = THIS_MODULE,
.poll = binder_poll,
.unlocked_ioctl = binder_ioctl,
.mmap = binder_mmap,
.open = binder_open,
.flush = binder_flush,
.release = binder_release,
};
static struct miscdevice binder_miscdev = {
.minor = MISC_DYNAMIC_MINOR,
.name = "binder",
.fops = &binder_fops
};
static int __init binder_init(void)
{
int ret;
binder_proc_dir_entry_root = proc_mkdir("binder", NULL);
if (binder_proc_dir_entry_root)
binder_proc_dir_entry_proc = proc_mkdir("proc", binder_proc_dir_entry_root);
ret = misc_register(&binder_miscdev);
if (binder_proc_dir_entry_root) {
create_proc_read_entry("state", S_IRUGO, binder_proc_dir_entry_root, binder_read_proc_state, NULL);
create_proc_read_entry("stats", S_IRUGO, binder_proc_dir_entry_root, binder_read_proc_stats, NULL);
create_proc_read_entry("transactions", S_IRUGO, binder_proc_dir_entry_root, binder_read_proc_transactions, NULL);
create_proc_read_entry("transaction_log", S_IRUGO, binder_proc_dir_entry_root, binder_read_proc_transaction_log, &binder_transaction_log);
create_proc_read_entry("failed_transaction_log", S_IRUGO, binder_proc_dir_entry_root, binder_read_proc_transaction_log, &binder_transaction_log_failed);
}
return ret;
}
device_initcall(binder_init);
...
getting the Service Manager proxy
frameworks/base/include/binder/IServiceManager.h
sp<IServiceManager> defaultServiceManager();
frameworks/base/libs/binder/IServiceManager.cpp
sp<IServiceManager> defaultServiceManager()
{
if (gDefaultServiceManager != NULL) return gDefaultServiceManager;
{
AutoMutex _l(gDefaultServiceManagerLock);
if (gDefaultServiceManager == NULL) {
gDefaultServiceManager = interface_cast<IServiceManager>(
ProcessState::self()->getContextObject(NULL));
}
}
return gDefaultServiceManager;
}
frameworks/base/libs/binder/Static.cpp
Mutex gDefaultServiceManagerLock;
sp<IServiceManager> gDefaultServiceManager;
class map
frameworks/base/include/binder/IInterface.h
template<typename INTERFACE>
class BpInterface : public INTERFACE, public BpRefBase
{
public:
BpInterface(const sp<IBinder>& remote);
protected:
virtual IBinder* onAsBinder();
};
...
start of Service
MediaPlayerService class map
frameworks/base/include/binder/IInterface.h
template<typename INTERFACE>
class BnInterface : public INTERFACE, public BBinder
{
public:
virtual sp<IInterface> queryLocalInterface(const String16& _descriptor);
virtual const String16& getInterfaceDescriptor() const;
protected:
virtual IBinder* onAsBinder();
};
frameworks/base/media/mediaserver/main_mediaserver.cpp
int main(int argc, char** argv)
{
sp<ProcessState> proc(ProcessState::self());
sp<IServiceManager> sm = defaultServiceManager();
LOGI("ServiceManager: %p", sm.get());
AudioFlinger::instantiate();
MediaPlayerService::instantiate();
CameraService::instantiate();
AudioPolicyService::instantiate();
ProcessState::self()->startThreadPool();
IPCThreadState::self()->joinThreadPool();
}
interaction
how to get Service proxy
BpMediaPlayerService class map
frameworks/base/media/libmedia//IMediaDeathNotifier.cpp
// establish binder interface to MediaPlayerService
/*static*/const sp<IMediaPlayerService>&
IMediaDeathNotifier::getMediaPlayerService()
{
LOGV("getMediaPlayerService");
Mutex::Autolock _l(sServiceLock);
if (sMediaPlayerService.get() == 0) {
sp<IServiceManager> sm = defaultServiceManager();
sp<IBinder> binder;
do {
binder = sm->getService(String16("media.player"));
if (binder != 0) {
break;
}
LOGW("Media player service not published, waiting...");
usleep(500000); // 0.5 s
} while(true);
if (sDeathNotifier == NULL) {
sDeathNotifier = new DeathNotifier();
}
binder->linkToDeath(sDeathNotifier);
sMediaPlayerService = interface_cast<IMediaPlayerService>(binder);
}
LOGE_IF(sMediaPlayerService == 0, "no media player service!?");
return sMediaPlayerService;
}
...
Java interface for Binder IPC Driver
1 getting the Java proxy of Service Manager
class ServiceManagerProxy
class ServiceManager
frameworks/base/core/java/android/os/ServiceManager.java
public final class ServiceManager {
......
private static IServiceManager sServiceManager;
......
private static IServiceManager getIServiceManager() {
if (sServiceManager != null) {
return sServiceManager;
}
// Find the service manager
sServiceManager = ServiceManagerNative.asInterface(BinderInternal.getContextObject());
return sServiceManager;
}
......
}
2 define the Java service
frameworks/base/core/java/android/os/IHelloService.aidl
package android.os;
interface IHelloService
{
void setVal(int val);
int getVal();
}
3 start of Java service
frameworks/base/services/java/com/android/server/HelloService.java
package com.android.server;
import android.content.Context;
import android.os.IHelloService;
import android.util.Slog;
public class HelloService extends IHelloService.Stub {
private static final String TAG = "HelloService";
HelloService() {
init_native();
}
public void setVal(int val) {
setVal_native(val);
}
public int getVal() {
return getVal_native();
}
private static native boolean init_native();
private static native void setVal_native(int val);
private static native int getVal_native();
}
4 getting Java service proxy
public class Hello extends Activity implements OnClickListener {
......
private IHelloService helloService = null;
......
@override
public void onCreate(Bundle savedInstanceState) {
helloService = IHelloService.Stub.asInterface(
ServiceManager.getService("hello"));
}
......
}
5 calling Java service
public class Hello extends Activity implements OnClickListener {
......
@override
public void onClick(View v) {
if(v.equals(readButton)) {
int val = helloService.getVal();
......
}
else if(v.equals(writeButton)) {
......
}
else if(v.equals(clearButton)) {
......
}
}
......
}
Thread merged to here
http://forum.xda-developers.com/showthread.php?t=2514846
Related
Basic android animation code
Here is the code for a basic animation program in Android: Code: [SIZE="2"][FONT="Courier New"]import android.app.*; import android.os.*; import android.view.*; import android.widget.*; import android.content.*; import android.graphics.*; import javax.xml.parsers.*; import javax.security.cert.*; public class MainActivity extends Activity { DrawView drawView = null; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setTitle("Animation Example"); drawView = new DrawView(this); setContentView(drawView); } @Override public void onPause() { super.onPause(); drawView.pause(); } @Override public void onResume() { super.onResume(); drawView.resume(); } } class DrawView extends SurfaceView implements SurfaceHolder.Callback { DrawThread thread = null; int screenWidth = 0; int screenHeight = 0; int radius = 40; int boundaryTop = 0; int boundaryBottom = 0; int boundaryLeft = 0; int boundaryRight = 0; float ppsX = 0; // horizontal velocity in pixels per second float ppsY = 0; // vertical " float x = 0; float y = 0; long lastDrawTime = 0; int minIntervalMs = 15; // limit frame rate Paint paint = null; public DrawView(Context context) { super(context); paint = new Paint(); paint.setAntiAlias(true); paint.setColor(Color.BLUE); getHolder().addCallback(this); setFocusable(true); } public void initialize(int screen_width, int screen_height) { screenWidth = screen_width; screenHeight = screen_height; x = screenWidth / 2.0f; y = screenHeight / 2.0f; boundaryTop = radius; boundaryBottom = screenHeight - radius - 1; boundaryLeft = radius; boundaryRight = screenWidth - radius - 1; ppsX = 250; ppsY = 100; } public void startThread() { thread = new DrawThread(getHolder()); thread.setRunning(true); thread.start(); } public void stopThread() { boolean retry = true; thread.setRunning(false); while (retry) { try { thread.join(); retry = false; } catch (InterruptedException e) { } } } public void pause() { stopThread(); lastDrawTime = 0; } public void resume() { } @Override public void surfaceCreated(SurfaceHolder holder) { startThread(); } @Override public void surfaceDestroyed(SurfaceHolder holder) { stopThread(); } @Override public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { } @Override public void onSizeChanged(int width_new, int height_new, int width_old, int height_old) { super.onSizeChanged(width_new, height_new, width_old, height_old); initialize(width_new, height_new); } @Override public synchronized boolean onTouchEvent(MotionEvent event) { switch (event.getAction()) { case MotionEvent.ACTION_DOWN: { break; } case MotionEvent.ACTION_UP: { break; } case MotionEvent.ACTION_MOVE: { break; } } return true; } public void updateCanvas(Canvas canvas) { if (lastDrawTime != 0) { long intervalMs = System.currentTimeMillis() - lastDrawTime; // interval in milliseconds if (intervalMs < minIntervalMs) { try { Thread.sleep(minIntervalMs - intervalMs); } catch (InterruptedException e) { } intervalMs = minIntervalMs; } float intervalS = intervalMs / 1000.0f; // interval in seconds x = x + intervalS * ppsX; if (x < boundaryLeft) { x = boundaryLeft; ppsX = -ppsX; } else if (x > boundaryRight) { x = boundaryRight; ppsX = -ppsX; } y = y + intervalS * ppsY; if (y < boundaryTop) { y = boundaryTop; ppsY = -ppsY; } else if (y > boundaryBottom) { y = boundaryBottom; ppsY = - ppsY; } } canvas.drawColor(Color.WHITE); canvas.drawCircle(x, y, radius, paint); lastDrawTime = System.currentTimeMillis(); } class DrawThread extends Thread { private SurfaceHolder holder = null; private boolean run = false; public DrawThread(SurfaceHolder holder) { this.holder = holder; } public void setRunning(boolean run) { this.run = run; } @Override public void run() { Canvas canvas = null; while (run) { canvas = null; try { canvas = holder.lockCanvas(null); synchronized (holder) { updateCanvas(canvas); } } finally { if (canvas != null) { holder.unlockCanvasAndPost(canvas); } } } } } } [/FONT][/SIZE]
[book]Inside Android: Learning Android build system by flashing CM ROM to oppo find5
Hi, all. Why this book? As experienced android developers or just beginners, sometimes you might have questions about what's going on inside android. Such as how activity starts, how service starts, etc. If we look into the code, we might have the answer, but it takes time and much effort. In fact, there's millions of lines of source code in android. Fortunately, Shengyang Luo wrote a book in chinese to clarify all these questions, with all the related knowledge he got in these years as an experienced engineer of linux/android. Now, he and I decide this book belongs to the android family, so to make more people get benefit from it, we will rewrite it in English. Pilot content Also, we want this book to be more adapted to your need, we might share the outline and part of the content of the book here, so that we all can discuss it while rewriting it. We might change the book according to your advice. For example, there might be more details for the parts you are most interested. To do this, we will have pilot passages soon. Which are you most interested in? Please share with us, and we will make it available ASAP. A more readable version is available in the attached. I will update it from time to time. Publishing We haven't talked with any press for publishing yet. So if any press is interested in publishing this book, please contact me. Contribute As you all know, writing is a tough job, especially when the book is regarding such a complicated android os system, so cheers, encouragement and donating are welcomed badly. Donating would help us not worry about making a living and dedicate to the writing or even hire some people to accelerate the progress. Please Rate the thread 5 Stars and click the Thanks Button! (any of my posts will do!) introduction to the content of the book The book would have 3 parts: say hello to android, drivers specific to android and understanding android in scenes. The first 2 parts are foundation knowledge for the third part, which is the major part of the book. Part I say hello to android includes 3 chapters, and introduces how to download the source code, build it, run it, smart pointer and Hardware Abstraction Layer(HAL). Since smart pointer is widely used in the native code of application framework, it would be very helpful if we get to know it before we dive into the scenes. Knowing HAL would help us understand the architecture of android, and then make the third part easier to learn. Part II drivers specific to android also includes 3 chapters, introducing 3 drivers specific to android: Logger Driver, Binder IPC Driver and Ashmem Shared Memory Driver. No doubt, these 3 drivers, especially the Binder IPC Driver, are the foundation of android. knowing about them would definitely help understand android. Part III understanding android in scenes includes more than 10 chapters, and introduces android in different scenes, such as the start of something(activity, service, zygote, service manager, etc.), process management, messaging handling etc. The book is based on android 2.3. If needed, we can rewrite it on newer version. outline Below is the outline of the book: Part I: say hello to android chapter 1 prerequisite 1.1 reference books on Linux kernel 1.2 reference books on Android application developing 1.3 download, build and run Android source code 1.3.1 download Android source code 1.3.2 build Android source code 1.3.3 run Android emulator 1.4 download, build and run Android kernel source code 1.4.1 download Android kernel source code 1.4.2 build Android kernel source code 1.4.3 run Android emulator 1.5 develop one Android application(example) 1.6 build and pack Android module independently 1.6.1 mmm: Builds all of the modules in the supplied directories 1.6.2 build one Android module independently 1.6.3 repack Android images chapter 2 Hardware Abstraction Layer(HAL) 2.1 develop Android hardware driver 2.1.1 implementation of one kernel driver 2.1.2 modify Kconfig of the kernel 2.1.3 modify Makefile of the kernel 2.1.4 build the driver 2.1.5 test the driver 2.2 test the driver with C executable 2.3 develop HAL module 2.3.1 specification for HAL module 2.3.2 interface for HAL module 2.3.3 load the HAL module 2.3.4 access permission for the hardware 2.4 develop service to the Android hardware 2.4.1 defite the service interface to hardware 2.4.2 implementation of the service 2.4.3 JNI interface for the service 2.4.4 start of the service 2.5 Android application on the service to hardware chapter 3 smart pointer 3.1 light weight pointer 3.1.1 implementation 3.1.2 example 3.2 strong pointer and weak pointer 3.2.1 strong pointer 3.2.2 weak pointer 3.2.3 example Part II: drivers specific to android chapter 4 Logger driver 4.1 Logger format 4.2 Logger driver 4.2.1 data structure 4.2.2 initialization 4.2.3 open the Logger driver 4.2.4 read the log 4.2.5 write the log 4.3 runtime library for the Logger driver 4.4 log interface for C/C++ 4.5 log interface for Java 4.6 Logcat tool 4.6.1 data structure 4.6.2 initialization 4.6.3 read the log 4.6.4 output the log chapter 5 Binder IPC Driver 5.1 Binder driver 5.1.1 data structure 5.1.2 initialization 5.1.3 open 5.1.4 mapping to the memory 5.1.5 kernel cache management 5.2 runtime library for Binder IPC Driver 5.3 example for Binder IPC Driver application 5.4 counting for Binder object reference 5.4.1 lifecycle of Binder local object 5.4.2 lifecycle of Binder instance 5.4.3 lifecycle of Binder reference 5.4.4 lifecycle of Binder proxy 5.5 Binder object death notification 5.5.1 register death notification 5.5.2 send death notification 5.5.3 unregister death notification 5.6 start of Service Manager 5.6.1 open and mapping on Binder 5.6.2 register as Binder context manager 5.6.3 wait for the Client request in loop 5.7 getting the Service Manager proxy 5.8 start of Service 5.8.1 register Service 5.8.2 start of Binder thread pool 5.9 how to get Service proxy 5.10 Java interface for Binder IPC Driver 5.10.1 getting the Java proxy of Service Manager 5.10.2 define the Java service 5.10.3 start of Java service 5.10.4 getting Java service proxy 5.10.5 calling Java service chapter 6 Ashmem Shared Memory Driver 6.1 Ashmem driver 6.1.1 data structure 6.1.2 initialization 6.1.3 open 6.1.4 mapping to the memory 6.1.5 lock and unlock 6.1.6 recycle 6.2 Ashmem interface in runtime library cutils 6.3 C++ interface for Ashmem 6.3.1 MemoryHeapBase 6.3.2 MemoryBase 6.3.3 example 6.4 Java interface for Ashmem 6.4.1 MemoryFile 6.4.2 example 6.5 how Ashmem shares memory Part III: understanding android in scenes chapter 7 start of Activity 7.1 Activity example 7.2 start of root Activity 7.3 start of child Activity in the same process 7.4 start of child Activity in the new process chapter 8 start of Service 8.1 Service example 8.2 start of Service in the same process 8.3 start of Service in the new process chapter 9 Broadcast 9.1 example 9.2 registerReceiver 9.3 send chapter 10 Content Provider 10.1 Content Provider example 10.1.1 ArticlesProvider 10.1.2 Article 10.2 start of Content Provider 10.3 data sharing of Content Provider 10.3.1 data sharing model 10.3.2 data transmission 10.4 Content Provider's notification for data Change 10.4.1 register ContentObserver 10.4.2 send notification for data Change chapter 11 start of Zygote and System process 11.1 start script of Zygote process 11.2 start of Zygote 11.3 start of System chapter 12 start of Android application 12.1 creation of application process 12.2 start of Binder thread pool 12.3 creation of message loop 12.4 start of Launcher chapter 13 message handling 13.1 creation of message queue 13.2 message cycle 13.3 message sending 13.4 message handling chapter 14 keyboard message handling 14.1 keyboard message handling model 14.2 start of InputManager 14.2.1 creation of InputManager 14.2.2 start of InputManager 14.2.3 start of InputDispatcher 14.2.4 start of InputReader 14.3 register InputChannel 14.3.1 creation of InputChannel 14.3.2 register InputChannel of server side 14.3.3 register the window of currently activated application 14.3.4 register InputChannel of client side 14.4 Dispatch of the keyboard message 14.4.1 InputReader gets keyboard event 14.4.2 InputDispatcher dispatch keyboard event 14.4.3 the window of currently activated application gets keyboard message 14.4.4 InputDispatcher gets notification when the keyboard event handling is done 14.5 unregister InputChannel 14.5.1 destroy application window 14.5.2 unregister InputChannel of client side 14.5.3 unregister InputChannel of server side chapter 15 message loop model of Android application thread 15.1 message loop model of application main thread 15.2 message loop model of nongraphic application child thread 15.3 message loop model of graphic application child thread chapter 16 installation and showup of Android application 16.1 installation of application 16.2 showup of application chapter 17 UI system 17.1 UI architecture 17.2 application(Activity) UI framework 17.2.1 creation of context 17.2.2 creation of window 17.2.3 creation of view 17.2.4 connection with WindowManagerService 17.2.5 creation of Surface 17.2.6 Measure, Layout and Draw 17.3 SurfaceFlinger 17.4 Multiple Display support chapter 18 resource management framework 18.1 resource management framework 18.2 compilation of resource 18.3 search for resource chapter 19 Dalvik virtual machine(DVM) 19.1 introduction 19.2 start of DVM 19.3 execution of DVM 19.4 register JNI methods 19.5 DVM process 19.6 DVM thread chapter 20 WindowManagerService 20.1 window size calculation 20.2 window management 20.3 Input Method Window management 20.4 Wallpaper Window management 20.5 Z order 20.6 Starting Window of Activity 20.7 App Transition 20.8 Transformation
WindowManagerService Part III: understanding android in scenes chapter 7 start of Activity 7.2 start of root Activity In Android, the app consists of Activity, so the start of app is actually the start of default Activity in the app. Here we will discuss how the app starts. The start of MainActivity is shown in the figure below: { "lightbox_close": "Close", "lightbox_next": "Next", "lightbox_previous": "Previous", "lightbox_error": "The requested content cannot be loaded. Please try again later.", "lightbox_start_slideshow": "Start slideshow", "lightbox_stop_slideshow": "Stop slideshow", "lightbox_full_screen": "Full screen", "lightbox_thumbnails": "Thumbnails", "lightbox_download": "Download", "lightbox_share": "Share", "lightbox_zoom": "Zoom", "lightbox_new_window": "New window", "lightbox_toggle_sidebar": "Toggle sidebar" } We will discuss every step in details in the following: Step 1. Launcher.startActivitySafely In Android, the app is started by Launcher. In fact, Launcher is also one app. When one app is installed, there will be on corresponding icon on the Launcher screen. When the icon is clicked, Launcher will start the app. The source of Launcher is in folder packages/apps/Launcher2, and the source to start other apps is in file src/com/android/launcher2/Launcher.java Code: /** * Default launcher application. */ public final class Launcher extends Activity implements View.OnClickListener, OnLongClickListener, LauncherModel.Callbacks, AllAppsView.Watcher { ...... /** * Launches the intent referred by the clicked shortcut. * * [user=955119]@param[/user] v The view representing the clicked shortcut. */ public void onClick(View v) { Object tag = v.getTag(); if (tag instanceof ShortcutInfo) { // Open shortcut final Intent intent = ((ShortcutInfo) tag).intent; int[] pos = new int[2]; v.getLocationOnScreen(pos); intent.setSourceBounds(new Rect(pos[0], pos[1], pos[0] + v.getWidth(), pos[1] + v.getHeight())); startActivitySafely(intent, tag); } else if (tag instanceof FolderInfo) { ...... } else if (v == mHandleView) { ...... } } void startActivitySafely(Intent intent, Object tag) { intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); try { startActivity(intent); } catch (ActivityNotFoundException e) { ...... } catch (SecurityException e) { ...... } } ...... } We already know that the default Activity of one app is MainActivity, and it's configed in AndroidManifest.xml: Code: <activity android:name=".MainActivity" android:label="@string/app_name"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> So, in the intent, action = "android.intent.action.Main", category="android.intent.category.LAUNCHER" and cmp="shy.luo.activity/.MainActivity". This means the Activity to start is shy.luo.activity.MainActivity. Intent.FLAG_ACTIVITY_NEW_TASK means it's going to start the Activity in a new Task. Task is different from Process. It's a group of Activity, managed in stack, last in first out. In fact, Task is very complicated. If you are interested in it, please visit http://developer.android.com/guide/topics/manifest/activity-element.html for more details. Here, we just need to know the MainActivity is going to start in a new Task, and that's enough. Step 2. Activity.startActivity In step 1, we see that Launcher is derived from Activity, and class Activity implements function startActivity, so, here function Activity.startActivity is called. The source is in file frameworks/base/core/java/android/app/Activity.java: Code: public class Activity extends ContextThemeWrapper implements LayoutInflater.Factory, Window.Callback, KeyEvent.Callback, OnCreateContextMenuListener, ComponentCallbacks { ...... @Override public void startActivity(Intent intent) { startActivityForResult(intent, -1); } ...... } This function is very simple, just calls startActivityForResult. The second argument -1 means no returned result is needed after the Activity ends. Step 3. Activity.startActivityForResult The source is also in file frameworks/base/core/java/android/app/Activity.java Code: public class Activity extends ContextThemeWrapper implements LayoutInflater.Factory, Window.Callback, KeyEvent.Callback, OnCreateContextMenuListener, ComponentCallbacks { ...... public void startActivityForResult(Intent intent, int requestCode) { if (mParent == null) { Instrumentation.ActivityResult ar = mInstrumentation.execStartActivity( this, mMainThread.getApplicationThread(), mToken, this, intent, requestCode); ...... } else { ...... } ...... } Minstrumentation is the data member of class Activity. Its type is Intrumentation, whose source is in file frameworks/base/core/java/android/app/Instrumentation.java. Intrumentation is used to monitor all of the interaction the system has with the application. Here, mMainThread is also the data member of class Activity. Its type is ActivityThread, and it represents the main thread of the app. We get data member ApplicationThread by mMainThread.getApplicationThread. It's a Binder, and ActivityManagerService uses it for IPC with ActivityThread. Here mMainThread is the main thread of Launcher. Here mToken is also the data member of class Activity. It's a remote interface of Binder. Step 4. Instrumentation.execStartActivity 12 Step 5. ActivityManagerProxy.startActivity 13 Step 6. ActivityManagerService.startActivity 14 Step 7.*ActivityStack.startActivityMayWait 15 Step 8. ActivityStack.startActivityLocked 18 Step 9. ActivityStack.startActivityUncheckedLocked 20 Step 10. Activity.resumeTopActivityLocked 24 Step 11. ActivityStack.startPausingLocked 25 Step 12.*ApplicationThreadProxy.schedulePauseActivity 27 Step 13. ApplicationThread.schedulePauseActivity 27 Step 14. ActivityThread.queueOrSendMessage 28 Step 15. H.handleMessage 29 Step 16.*ActivityThread.handlePauseActivity 30 Step 17. ActivityManagerProxy.activityPaused 31 Step 18.*ActivityManagerService.activityPaused 32 Step 20.*ActivityStack.completePauseLocked 33 Step 21.*ActivityStack.resumeTopActivityLokced 34 Step 22. ActivityStack.startSpecificActivityLocked 36 Step 23.*ActivityManagerService.startProcessLocked 37 Step 24. ActivityThread.main 39 Step 25.*ActivityManagerProxy.attachApplication 41 Step 26.*ActivityManagerService.attachApplication 41 Step 27.*ActivityManagerService.attachApplicationLocked 42 Step 28. ActivityStack.realStartActivityLocked 44 Step 29.*ApplicationThreadProxy.scheduleLaunchActivity 46 Step 30.*ApplicationThread.scheduleLaunchActivity 47 Step 31.*ActivityThread.queueOrSendMessage 48 Step 32. H.handleMessage 49 Step 33.*ActivityThread.handleLaunchActivity 50 Step 34.*ActivityThread.performLaunchActivity 51 Step 35. MainActivity.onCreate 54 chapter 20 WindowManagerService 20.1 window size calculation At any time, there's only one active Activity window in android. But, for WindowManagerService, it doesn't mean it only needs to manage one Activity window. For example, during the transition of two apps, two Activity windows are both visible. Even when there's only one Activity window is visible, WindowManagerService still has to manage multiple windows at the same time, since visible Activity window might have Wallpaper Winodw or Sub Window, and possibly Status Bar and Input Method Window would show up, as shown in the diagram below: 20.2 window management As you know, in Android, Activity is managed as stack by ActivityManagerService. Similar to Activity, Window is also managed as stack by WindowManagerService. The higher Windows in the stack is above those lower windows. Here we will discuss how WindowManagerService manages windows as stack. From chapter 7, we know that for each Activity there's one ActivityRecord in ActivityManagerService. Also, for each ActivityRecord there's one AppWindowToken in WindowManagerService. In addition to that, for each inputmethodwindow there's one binder in InputMethodManagerService, and correspondingly one WindowToken in WindowManagerService. Similar to inputmethodwindow, for each Wallpaperwindow there's one binder in WallpaperManagerService, and correspondingly one WindowToken in WindowManagerService. In WindowManagerService, Windows(WindowState) are organized as groups, and windows in the same groups have the same token( AppWindowToken and WindowToken ). For example, one Activity window can have a Starting Window, and several child windows, then all these windows are in the same group, and use the AppWindowToken of the Activity window as token. The above relationship is shown in the figure below: In the above figure, Activity Stack is created by ActivityManagerService, Token List and Window Stack are created by WindowManagerService, Binder for IM is created by InputMethodManagerService for a InputMethodWindow, and Binder for WP is created by WallpaperManagerService for a WallpaperWindow. Relationship of objects in the above figure is shown as below: 1. ActivityRecord-J corresponds to AppWindowToken-J, which identifies a group of windows: {WindowState- A,*WindowState-B,*WindowState-B-1}. WindowState-B-1 is the child window of WindowState-B. 2. ActivityRecord-K corresponds to AppWindowToken-K, which identifies a group of windows: {WindowState-C, WindowState-C-1, WindowState-D, WindowState-D-1}. WindowState-C-1 is the child window of WindowState-C, and WindowState-D-1 is the child window of WindowState-D. 20.3 Input Method Window management In Android, inputmethod window is a kind of special window, and it's always on top of the window who knows it. So once WindowManagerService knows the focused window needs inputmethod, it will adjust the position of inputmethod window in the window stack, and make it on top of the focused window, so that the user can input character by inputmethod window. We will discuss how WindowManagerService manages inputmethod window in details here. In android, except for Inputmethod Window, there's another kind of window called Input Method Dialog, which is always on top of Input Method Window. The relationship between Activity window, Input Method Window and Input Method Dialog is shown as the figure below: 20.4 Wallpaper Window management In Android, Wallpaper Window, just like the Input Method Window, is also a special kind of window, and they both love to stay with a normal Activity Window. Input Method Window is on the top, Wallpaper Window is at the bottom, and Activity Window is in the middle. We already know how Input Method Window is on top of Activity Window, and here we will discuss how Wallpaper Window stays at the bottom of Activity Window. If one Activity Window needs to show the wallpaper, it must fulfill the following two conditions: 1. the background is Translucent. For example, its android:theme property in file AndroidManifest.xml must be set to Theme.Translucent Code: <activity android:name=".WallpaperActivity" android:theme="@android:style/Theme.Translucent"> ...... </activity>
implementation of one kernel driver for android 1. mkdir hello [email protected]MACHINE-NAME:~/Android$ cd kernel/common/drivers [email protected]:~/Android/kernel/common/drivers$ mkdir hello 2. hello.h #ifndef _HELLO_ANDROID_H_ #define _HELLO_ANDROID_H_ #include <linux/cdev.h> #include <linux/semaphore.h> #define HELLO_DEVICE_NODE_NAME "hello" #define HELLO_DEVICE_FILE_NAME "hello" #define HELLO_DEVICE_PROC_NAME "hello" #define HELLO_DEVICE_CLASS_NAME "hello" struct hello_android_dev { int val; struct semaphore sem; struct cdev dev; }; #endif 3. hello.c #include <linux/init.h> #include <linux/module.h> #include <linux/types.h> #include <linux/fs.h> #include <linux/proc_fs.h> #include <linux/device.h> #include <asm/uaccess.h> #include "hello.h" static int hello_major = 0; static int hello_minor = 0; static struct class* hello_class = NULL; static struct hello_android_dev* hello_dev = NULL; static int hello_open(struct inode* inode, struct file* filp); static int hello_release(struct inode* inode, struct file* filp); static ssize_t hello_read(struct file* filp, char __user *buf, size_t count, loff_t* f_pos); static ssize_t hello_write(struct file* filp, const char __user *buf, size_t count, loff_t* f_pos); static struct file_operations hello_fops = { .owner = THIS_MODULE, .open = hello_open, .release = hello_release, .read = hello_read, .write = hello_write, }; static ssize_t hello_val_show(struct device* dev, struct device_attribute* attr, char* buf); static ssize_t hello_val_store(struct device* dev, struct device_attribute* attr, const char* buf, size_t count); static DEVICE_ATTR(val, S_IRUGO | S_IWUSR, hello_val_show, hello_val_store); static int hello_open(struct inode* inode, struct file* filp) { struct hello_android_dev* dev; dev = container_of(inode->i_cdev, struct hello_android_dev, dev); filp->private_data = dev; return 0; } static int hello_release(struct inode* inode, struct file* filp) { return 0; } static ssize_t hello_read(struct file* filp, char __user *buf, size_t count, loff_t* f_pos) { ssize_t err = 0; struct hello_android_dev* dev = filp->private_data; if(down_interruptible(&(dev->sem))) { return -ERESTARTSYS; } if(count < sizeof(dev->val)) { goto out; } if(copy_to_user(buf, &(dev->val), sizeof(dev->val))) { err = -EFAULT; goto out; } err = sizeof(dev->val); out: up(&(dev->sem)); return err; } static ssize_t hello_write(struct file* filp, const char __user *buf, size_t count, loff_t* f_pos) { struct hello_android_dev* dev = filp->private_data; ssize_t err = 0; if(down_interruptible(&(dev->sem))) { return -ERESTARTSYS; } if(count != sizeof(dev->val)) { goto out; } if(copy_from_user(&(dev->val), buf, count)) { err = -EFAULT; goto out; } err = sizeof(dev->val); out: up(&(dev->sem)); return err; } static ssize_t __hello_get_val(struct hello_android_dev* dev, char* buf) { int val = 0; if(down_interruptible(&(dev->sem))) { return -ERESTARTSYS; } val = dev->val; up(&(dev->sem)); return snprintf(buf, PAGE_SIZE, "%d\n", val); } static ssize_t __hello_set_val(struct hello_android_dev* dev, const char* buf, size_t count) { int val = 0; val = simple_strtol(buf, NULL, 10); if(down_interruptible(&(dev->sem))) { return -ERESTARTSYS; } dev->val = val; up(&(dev->sem)); return count; } static ssize_t hello_val_show(struct device* dev, struct device_attribute* attr, char* buf) { struct hello_android_dev* hdev = (struct hello_android_dev*)dev_get_drvdata(dev); return __hello_get_val(hdev, buf); } static ssize_t hello_val_store(struct device* dev, struct device_attribute* attr, const char* buf, size_t count) { struct hello_android_dev* hdev = (struct hello_android_dev*)dev_get_drvdata(dev); return __hello_set_val(hdev, buf, count); } static ssize_t hello_proc_read(char* page, char** start, off_t off, int count, int* eof, void* data) { if(off > 0) { *eof = 1; return 0; } return __hello_get_val(hello_dev, page); } static ssize_t hello_proc_write(struct file* filp, const char __user *buff, unsigned long len, void* data) { int err = 0; char* page = NULL; if(len > PAGE_SIZE) { printk(KERN_ALERT"The buff is too large: %lu.\n", len); return -EFAULT; } page = (char*)__get_free_page(GFP_KERNEL); if(!page) { printk(KERN_ALERT"Failed to alloc page.\n"); return -ENOMEM; } if(copy_from_user(page, buff, len)) { printk(KERN_ALERT"Failed to copy buff from user.\n"); err = -EFAULT; goto out; } err = __hello_set_val(hello_dev, page, len); out: free_page((unsigned long)page); return err; } static void hello_create_proc(void) { struct proc_dir_entry* entry; entry = create_proc_entry(HELLO_DEVICE_PROC_NAME, 0, NULL); if(entry) { entry->owner = THIS_MODULE; entry->read_proc = hello_proc_read; entry->write_proc = hello_proc_write; } } static void hello_remove_proc(void) { remove_proc_entry(HELLO_DEVICE_PROC_NAME, NULL); } static int __hello_setup_dev(struct hello_android_dev* dev) { int err; dev_t devno = MKDEV(hello_major, hello_minor); memset(dev, 0, sizeof(struct hello_android_dev)); cdev_init(&(dev->dev), &hello_fops); dev->dev.owner = THIS_MODULE; dev->dev.ops = &hello_fops; err = cdev_add(&(dev->dev),devno, 1); if(err) { return err; } init_MUTEX(&(dev->sem)); dev->val = 0; return 0; } static int __init hello_init(void){ int err = -1; dev_t dev = 0; struct device* temp = NULL; printk(KERN_ALERT"Initializing hello device.\n"); err = alloc_chrdev_region(&dev, 0, 1, HELLO_DEVICE_NODE_NAME); if(err < 0) { printk(KERN_ALERT"Failed to alloc char dev region.\n"); goto fail; } hello_major = MAJOR(dev); hello_minor = MINOR(dev); hello_dev = kmalloc(sizeof(struct hello_android_dev), GFP_KERNEL); if(!hello_dev) { err = -ENOMEM; printk(KERN_ALERT"Failed to alloc hello_dev.\n"); goto unregister; } err = __hello_setup_dev(hello_dev); if(err) { printk(KERN_ALERT"Failed to setup dev: %d.\n", err); goto cleanup; } hello_class = class_create(THIS_MODULE, HELLO_DEVICE_CLASS_NAME); if(IS_ERR(hello_class)) { err = PTR_ERR(hello_class); printk(KERN_ALERT"Failed to create hello class.\n"); goto destroy_cdev; } temp = device_create(hello_class, NULL, dev, "%s", HELLO_DEVICE_FILE_NAME); if(IS_ERR(temp)) { err = PTR_ERR(temp); printk(KERN_ALERT"Failed to create hello device."); goto destroy_class; } err = device_create_file(temp, &dev_attr_val); if(err < 0) { printk(KERN_ALERT"Failed to create attribute val."); goto destroy_device; } dev_set_drvdata(temp, hello_dev); hello_create_proc(); printk(KERN_ALERT"Succedded to initialize hello device.\n"); return 0; destroy_device: device_destroy(hello_class, dev); destroy_class: class_destroy(hello_class); destroy_cdev: cdev_del(&(hello_dev->dev)); cleanup: kfree(hello_dev); unregister: unregister_chrdev_region(MKDEV(hello_major, hello_minor), 1); fail: return err; } static void __exit hello_exit(void) { dev_t devno = MKDEV(hello_major, hello_minor); printk(KERN_ALERT"Destroy hello device.\n"); hello_remove_proc(); if(hello_class) { device_destroy(hello_class, MKDEV(hello_major, hello_minor)); class_destroy(hello_class); } if(hello_dev) { cdev_del(&(hello_dev->dev)); kfree(hello_dev); } unregister_chrdev_region(devno, 1); } MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("First Android Driver"); module_init(hello_init); module_exit(hello_exit); 4. things added to Kconfig Makefile Kconfig: config HELLO tristate "First Android Driver" default n help This is the first android driver. Makefile: obj-$(CONFIG_HELLO) += hello.o 5. menu menuconfig In arch/arm/Kconfig and drivers/kconfig, add one line between menu "Device Drivers" and endmenu: source "drivers/hello/Kconfig" 6. change drivers/Makefile, add one line: obj-$(CONFIG_HELLO) += hello/ 7. menuconfig [email protected]:~/Android/kernel/common$ make menuconfig set option "Device Drivers" => "First Android Drivers" to "y" 8. make [email protected]:~/Android/kernel/common$ make 9. rebuild kernel and test the driver [email protected]:~/Android$ emulator -kernel ./kernel/common/arch/arm/boot/zImage & [email protected]:~/Android$ adb shell File hello should be available in /dev: [email protected]:/ # cd dev [email protected]:/dev # ls File hello should be available in /proc: [email protected]:/ # cd proc [email protected]:/proc # ls Get the value: [email protected]:/proc # cat hello 0 [email protected]:/proc # echo '5' > hello [email protected]:/proc # cat hello 5 Dir hello should be available in /sys/class: [email protected]:/ # cd sys/class [email protected]:/sys/class # ls Dir hello should be available in /sys/class/hello: [email protected]:/sys/class # cd hello [email protected]:/sys/class/hello # ls File val should be available in /sys/class/hello/hello: [email protected]:/sys/class/hello # cd hello [email protected]:/sys/class/hello/hello # ls access the value of val: [email protected]:/sys/class/hello/hello # cat val 5 [email protected]:/sys/class/hello/hello # echo '0' > val [email protected]:/sys/class/hello/hello # cat val 0
build one module of Android alone 1. run envsetup.sh [email protected]:~/Android$ . ./build/envsetup.sh after this, there would be some extra commands available: - croot: Changes directory to the top of the tree. - m: Makes from the top of the tree. - mm: Builds all of the modules in the current directory. - mmm: Builds all of the modules in the supplied directories. - cgrep: Greps on all local C/C++ files. - jgrep: Greps on all local Java files. - resgrep: Greps on all local res/*.xml files. - godir: Go to the directory containing a file. 2. use mmm to build the module, such as Email app: [email protected]:~/Android$ mmm packages/apps/Email/ After building, there would be one Email.apk in out/target/product/generic/system/app, where all app files are located here. Also, out/target/product/generic/system/bin for exexcutable, out/target/product/generic/system/lib for library, and out/target/product/generic/system/lib/hw for HAL interface files. 3. repack system.img [email protected]:~/Android$ make snod 4. run emulator [email protected]:~/Android$ emulator
HAL in android please read the attached for details.
test the driver with C executable 1. mkdir hello [email protected]:~/Android$ cd external [email protected]:~/Android/external$ mkdir hello 2. hello.c #include <stdio.h> #include <stdlib.h> #include <fcntl.h> #define DEVICE_NAME "/dev/hello" int main(int argc, char** argv) { int fd = -1; int val = 0; fd = open(DEVICE_NAME, O_RDWR); if(fd == -1) { printf("Failed to open device %s.\n", DEVICE_NAME); return -1; } printf("Read original value:\n"); read(fd, &val, sizeof(val)); printf("%d.\n\n", val); val = 5; printf("Write value %d to %s.\n\n", val, DEVICE_NAME); write(fd, &val, sizeof(val)); printf("Read the value again:\n"); read(fd, &val, sizeof(val)); printf("%d.\n\n", val); close(fd); return 0; } 3. Android.mk LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE_TAGS := optional LOCAL_MODULE := hello LOCAL_SRC_FILES := $(call all-subdir-c-files) include $(BUILD_EXECUTABLE) 4. mmm [email protected]:~/Android$ mmm ./external/hello 5. repack system.img [email protected]:~/Android$ make snod 6. run /system/bin/hello [email protected]:~/Android$ emulator -kernel ./kernel/common/arch/arm/boot/zImage & [email protected]:~/Android$ adb shell [email protected]:/ # cd system/bin [email protected]:/system/bin # ./hello Read the original value: 0. Write value 5 to /dev/hello. Read the value again: 5.
HAL module for the driver 1. hello.h in hardware/libhardware/include/hardware [email protected]:~/Android$ cd hardware/libhardware/include/hardware [email protected]:~/Android/hardware/libhardware/include/hardware$ vi hello.h #ifndef ANDROID_HELLO_INTERFACE_H #define ANDROID_HELLO_INTERFACE_H #include <hardware/hardware.h> __BEGIN_DECLS #define HELLO_HARDWARE_MODULE_ID "hello" struct hello_module_t { struct hw_module_t common; }; struct hello_device_t { struct hw_device_t common; int fd; int (*set_val)(struct hello_device_t* dev, int val); int (*get_val)(struct hello_device_t* dev, int* val); }; __END_DECLS #endif 2. hello.c in hardware/libhardware/modules #define LOG_TAG "HelloStub" #include <hardware/hardware.h> #include <hardware/hello.h> #include <fcntl.h> #include <errno.h> #include <cutils/log.h> #include <cutils/atomic.h> #define DEVICE_NAME "/dev/hello" #define MODULE_NAME "Hello" #define MODULE_AUTHOR "[email protected]" /*open and close the device*/ static int hello_device_open(const struct hw_module_t* module, const char* name, struct hw_device_t** device); static int hello_device_close(struct hw_device_t* device); /*get and set the value*/ static int hello_set_val(struct hello_device_t* dev, int val); static int hello_get_val(struct hello_device_t* dev, int* val); static struct hw_module_methods_t hello_module_methods = { open: hello_device_open }; /*module info*/ struct hello_module_t HAL_MODULE_INFO_SYM = { common: { tag: HARDWARE_MODULE_TAG, version_major: 1, version_minor: 0, id: HELLO_HARDWARE_MODULE_ID, name: MODULE_NAME, author: MODULE_AUTHOR, methods: &hello_module_methods, } }; static int hello_device_open(const struct hw_module_t* module, const char* name, struct hw_device_t** device) { struct hello_device_t* dev;dev = (struct hello_device_t*)malloc(sizeof(struct hello_device_t)); if(!dev) { LOGE("Hello Stub: failed to alloc space"); return -EFAULT; } memset(dev, 0, sizeof(struct hello_device_t)); dev->common.tag = HARDWARE_DEVICE_TAG; dev->common.version = 0; dev->common.module = (hw_module_t*)module; dev->common.close = hello_device_close; dev->set_val = hello_set_val;dev->get_val = hello_get_val; if((dev->fd = open(DEVICE_NAME, O_RDWR)) == -1) { LOGE("Hello Stub: failed to open /dev/hello -- %s.", strerror(errno));free(dev); return -EFAULT; } *device = &(dev->common); LOGI("Hello Stub: open /dev/hello successfully."); return 0; } static int hello_device_close(struct hw_device_t* device) { struct hello_device_t* hello_device = (struct hello_device_t*)device; if(hello_device) { close(hello_device->fd); free(hello_device); } return 0; } static int hello_set_val(struct hello_device_t* dev, int val) { LOGI("Hello Stub: set value %d to device.", val); write(dev->fd, &val, sizeof(val)); return 0; } static int hello_get_val(struct hello_device_t* dev, int* val) { if(!val) { LOGE("Hello Stub: error val pointer"); return -EFAULT; } read(dev->fd, val, sizeof(*val)); LOGI("Hello Stub: get value %d from device", *val); return 0; } 3. Android.mk LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE_TAGS := optional LOCAL_PRELINK_MODULE := false LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/hw LOCAL_SHARED_LIBRARIES := liblog LOCAL_SRC_FILES := hello.c LOCAL_MODULE := hello.default include $(BUILD_SHARED_LIBRARY) 4. build [email protected]:~/Android$ mmm hardware/libhardware/modules/hello you will get hello.default.so in out/target/product/generic/system/lib/hw 5. repack system.img [email protected]:~/Android$ make snod
inside android http://forum.xda-developers.com/showthread.php?t=2514846 I'm fresh in xda, so I can't post in "Android Development and Hacking > Android Software and Hacking General [Developers Only] ". Instead, I have to post on gerneral forum. the location of previous post is http://forum.xda-developers.com/showthread.php?t=2514846. We haven't talked with any press for publishing yet. So if any press is interested in publishing this book, please contact me. As you all know, writing is a tough job, especially when the book is regarding such a complicated android os system, so cheers, encouragement and funding are welcomed badly. Funding would help us not worry about making a living and dedicate to the writing or even hire some people to accelerate the progress. For funding, please visit: mod edit Please Rate the thread 5 Stars and click the Thanks Button! (any of my posts will do!)
JAVA interface for HAL module sorry, the title should be JNI interface for HAL module 1. new com_android_server_HelloService.cpp [email protected]:~/Android$ cd frameworks/base/services/jni [email protected]:~/Android/frameworks/base/services/jni$ vi com_android_server_HelloService.cpp #define LOG_TAG "HelloService" #include "jni.h" #include "JNIHelp.h" #include "android_runtime/AndroidRuntime.h" #include <utils/misc.h> #include <utils/Log.h> #include <hardware/hardware.h> #include <hardware/hello.h> #include <stdio.h> namespace android { /*在硬件抽象层中定义的硬件访问结构体,参考<hardware/hello.h>*/ struct hello_device_t* hello_device = NULL; /*通过硬件抽象层定义的硬件访问接口设置硬件寄存器val的值*/ static void hello_setVal(JNIEnv* env, jobject clazz, jint value) { int val = value; LOGI("Hello JNI: set value %d to device.", val); if(!hello_device) { LOGI("Hello JNI: device is not open."); return; } hello_device->set_val(hello_device, val); } /*通过硬件抽象层定义的硬件访问接口读取硬件寄存器val的值*/ static jint hello_getVal(JNIEnv* env, jobject clazz) { int val = 0; if(!hello_device) { LOGI("Hello JNI: device is not open."); return val; } hello_device->get_val(hello_device, &val); LOGI("Hello JNI: get value %d from device.", val); return val; } /*通过硬件抽象层定义的硬件模块打开接口打开硬件设备*/ static inline int hello_device_open(const hw_module_t* module, struct hello_device_t** device) { return module->methods->open(module, HELLO_HARDWARE_MODULE_ID, (struct hw_device_t**)device); } /*通过硬件模块ID来加载指定的硬件抽象层模块并打开硬件*/ static jboolean hello_init(JNIEnv* env, jclass clazz) { hello_module_t* module; LOGI("Hello JNI: initializing......"); if(hw_get_module(HELLO_HARDWARE_MODULE_ID, (const struct hw_module_t**)&module) == 0) { LOGI("Hello JNI: hello Stub found."); if(hello_device_open(&(module->common), &hello_device) == 0) { LOGI("Hello JNI: hello device is open."); return 0; } LOGE("Hello JNI: failed to open hello device."); return -1; } LOGE("Hello JNI: failed to get hello stub module."); return -1; } /*JNI方法表*/ static const JNINativeMethod method_table[] = { {"init_native", "()Z", (void*)hello_init}, {"setVal_native", "(I)V", (void*)hello_setVal}, {"getVal_native", "()I", (void*)hello_getVal}, }; /*注册JNI方法*/ int register_android_server_HelloService(JNIEnv *env) { return jniRegisterNativeMethods(env, "com/android/server/HelloService", method_table, NELEM(method_table)); } }; 2. modify onload.cpp in frameworks/base/services/jni add register_android_server_HelloService to namespace android namespace android { .............................................................................................. int register_android_server_HelloService(JNIEnv *env); }; 在JNI_onLoad增加register_android_server_HelloService函数调用: extern "C" jint JNI_onLoad(JavaVM* vm, void* reserved) { ................................................................................................. register_android_server_HelloService(env); ................................................................................................. } 3. modify Android.mk in frameworks/base/services/jni, add com_android_server_HelloService.cpp LOCAL_SRC_FILES:= \ com_android_server_AlarmManagerService.cpp \ com_android_server_BatteryService.cpp \ com_android_server_InputManager.cpp \ com_android_server_LightsService.cpp \ com_android_server_PowerManagerService.cpp \ com_android_server_SystemServer.cpp \ com_android_server_UsbService.cpp \ com_android_server_VibratorService.cpp \ com_android_server_location_GpsLocationProvider.cpp \ com_android_server_HelloService.cpp / onload.cpp 4. build and repack system.img [email protected]:~/Android$ mmm frameworks/base/services/jni [email protected]:~/Android$ make snod
service to the Android hardware 1. defite the service interface to hardware [email protected]:~/Android$ cd frameworks/base/core/java/android/os [email protected]:~/Android/frameworks/base/core/java/android/os$ vi IHelloService.aidl package android.os; interface IHelloService { void setVal(int val); int getVal(); } 2. modify Android.mk in frameworks/base, add IHelloService.aidl to LOCAL_SRC_FILES ## READ ME: ######################################################## ## ## When updating this list of aidl files, consider if that aidl is ## part of the SDK API. If it is, also add it to the list below that ## is preprocessed and distributed with the SDK. This list should ## not contain any aidl files for parcelables, but the one below should ## if you intend for 3rd parties to be able to send those objects ## across process boundaries. ## ## READ ME: ######################################################## LOCAL_SRC_FILES += / .................................................................... core/java/android/os/IVibratorService.aidl / core/java/android/os/IHelloService.aidl / core/java/android/service/urlrenderer/IUrlRendererService.aidl / ..................................................................... 3. build [email protected]:~/Android$ mmm frameworks/base 4. new HelloService.java in frameworks/base/services/java/com/android/server package com.android.server; import android.content.Context; import android.os.IHelloService; import android.util.Slog; public class HelloService extends IHelloService.Stub { private static final String TAG = "HelloService"; HelloService() { init_native(); } public void setVal(int val) { setVal_native(val); } public int getVal() { return getVal_native(); } private static native boolean init_native(); private static native void setVal_native(int val); private static native int getVal_native(); }; 5. modify SystemServer.java in frameworks/base/services/java/com/android/server, change ServerThread::run @override public void run() { .................................................................................... try { Slog.i(TAG, "DiskStats Service"); ServiceManager.addService("diskstats", new DiskStatsService(context)); } catch (Throwable e) { Slog.e(TAG, "Failure starting DiskStats Service", e); } try { Slog.i(TAG, "Hello Service"); ServiceManager.addService("hello", new HelloService()); } catch (Throwable e) { Slog.e(TAG, "Failure starting Hello Service", e); } ...................................................................................... } 6. build HelloService and repack system.img [email protected]:~/Android$ mmm frameworks/base/services/java [email protected]:~/Android$ make snod
Android test application on the service to hardware 1. Hello.java package shy.luo.hello; import shy.luo.hello.R; import android.app.Activity; import android.os.ServiceManager; import android.os.Bundle; import android.os.IHelloService; import android.os.RemoteException; import android.util.Log; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; import android.widget.EditText; public class Hello extends Activity implements OnClickListener { private final static String LOG_TAG = "shy.luo.renju.Hello"; private IHelloService helloService = null; private EditText valueText = null; private Button readButton = null; private Button writeButton = null; private Button clearButton = null; /** Called when the activity is first created. */ @override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); helloService = IHelloService.Stub.asInterface( ServiceManager.getService("hello")); valueText = (EditText)findViewById(R.id.edit_value); 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(LOG_TAG, "Hello Activity Created"); } @override public void onClick(View v) { if(v.equals(readButton)) { try { int val = helloService.getVal(); String text = String.valueOf(val); valueText.setText(text); } catch (RemoteException e) { Log.e(LOG_TAG, "Remote Exception while reading value from device."); } } else if(v.equals(writeButton)) { try { String text = valueText.getText().toString(); int val = Integer.parseInt(text); helloService.setVal(val); } catch (RemoteException e) { Log.e(LOG_TAG, "Remote Exception while writing value to device."); } } else if(v.equals(clearButton)) { String text = ""; valueText.setText(text); } } } res/layout/main.xml <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" androidrientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent"> <LinearLayout android:layout_width="fill_parent" android:layout_height="wrap_content" androidrientation="vertical" android:gravity="center"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/value"> </TextView> <EditText android:layout_width="fill_parent" android:layout_height="wrap_content" android:id="@+id/edit_value" android:hint="@string/hint"> </EditText> </LinearLayout> <LinearLayout android:layout_width="fill_parent" android:layout_height="wrap_content" androidrientation="horizontal" android:gravity="center"> <Button android:id="@+id/button_read" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/read"> </Button> <Button android:id="@+id/button_write" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/write"> </Button> <Button android:id="@+id/button_clear" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/clear"> </Button> </LinearLayout> </LinearLayout> res/values/strings.xml: <?xml version="1.0" encoding="utf-8"?> <resources> <string name="app_name">Hello</string> <string name="value">Value</string> <string name="hint">Please input a value...</string> <string name="read">Read</string> <string name="write">Write</string> <string name="clear">Clear</string> </resources> AndroidManifest.xml: <?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="shy.luo.hello" android:versionCode="1" android:versionName="1.0"> <application android:icon="@drawable/icon" android:label="@string/app_name"> <activity android:name=".Hello" android:label="@string/app_name"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application> </manifest> 2. Android.mk copy dir Hello to packages/experimental, add Android.mk: [email protected]:~/Android/packages/experimental$ vi Android.mk LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE_TAGS := optional LOCAL_SRC_FILES := $(call all-subdir-java-files) LOCAL_PACKAGE_NAME := Hello include $(BUILD_PACKAGE) 3. build hello and repack system.img [email protected]:~/Android$ mmm packages/experimental/Hello [email protected]:~/Android$ make snod
log in android 1. kernel log <linux/kernel.h> #define KERN_EMERG "<0>" /* system is unusable */ #define KERN_ALERT "<1>" /* action must be taken immediately */ #define KERN_CRIT "<2>" /* critical conditions */ #deinfe KERN_ERR "<3>" /* error conditions */ #deinfe KERN_WARNING "<4>" /* warning conditions */ #deinfe KERN_NOTICE "<5>" /* normal but significant condition */ #deinfe KERN_INFO "<6>" /* informational */ #deinfe KERN_DEBUG "<7>" /* debug-level messages */ printk(KERN_ALERT"This is the log printed by printk in linux kernel space."); to read the log: [email protected]:~/Android$ emulator & [email protected]:~/Android$ adb shell [email protected]:/ # cat /proc/kmsg 2. LOG for app C/C++: system/core/include/android/log.h /* * Android log priority values, in ascending priority order. */ 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; system/core/include/cutils/log.h /* * This is the local tag used for the following simplified * logging macros. You can change this preprocessor definition * before using the other macros to change the tag. */ #ifndef LOG_TAG #define LOG_TAG NULL #endif /* * Simplified macro to send a verbose log message using the current LOG_TAG. */ #ifndef LOGV #if LOG_NDEBUG #define LOGV(...) ((void)0) #else #define LOGV(...) ((void)LOG(LOG_VERBOSE, LOG_TAG, __VA_ARGS__)) #endif #endif /* * Basic log message macro. * * Example: * LOG(LOG_WARN, NULL, "Failed with error %d", errno); * * The second argument may be NULL or "" to indicate the "global" tag. */ #ifndef LOG #define LOG(priority, tag, ...) \ LOG_PRI(ANDROID_##priority, tag, __VA_ARGS__) #endif /* * Log macro that allows you to specify a number for priority. */ #ifndef LOG_PRI #define LOG_PRI(priority, tag, ...) \ android_printLog(priority, tag, __VA_ARGS__) #endif /* * ================================================================ * * The stuff in the rest of this file should not be used directly. */ #define android_printLog(prio, tag, fmt...) \ __android_log_print(prio, tag, fmt) to use: #define LOG_TAG "MY LOG TAG" #include <cutils/log.h> LOGV("This is the log printed by LOGV in android user space."); java: frameworks/base/core/java/android/util/Log.java ................................................ public final class Log { ................................................ /** * Priority constant for the println method; use Log.v. */ public static final int VERBOSE = 2; /** * Priority constant for the println method; use Log.d. */ public static final int DEBUG = 3; /** * Priority constant for the println method; use Log.i. */ public static final int INFO = 4; /** * Priority constant for the println method; use Log.w. */ public static final int WARN = 5; /** * Priority constant for the println method; use Log.e. */ public static final int ERROR = 6; /** * Priority constant for the println method. */ public static final int ASSERT = 7; ..................................................... public static int v(String tag, String msg) { return println_native(LOG_ID_MAIN, VERBOSE, tag, msg); } public static int v(String tag, String msg, Throwable tr) { return println_native(LOG_ID_MAIN, VERBOSE, tag, msg + '\n' + getStackTraceString(tr)); } public static int d(String tag, String msg) { return println_native(LOG_ID_MAIN, DEBUG, tag, msg); } public static int d(String tag, String msg, Throwable tr) { return println_native(LOG_ID_MAIN, DEBUG, tag, msg + '\n' + getStackTraceString(tr)); } public static int i(String tag, String msg) { return println_native(LOG_ID_MAIN, INFO, tag, msg); } public static int i(String tag, String msg, Throwable tr) { return println_native(LOG_ID_MAIN, INFO, tag, msg + '\n' + getStackTraceString(tr)); } public static int w(String tag, String msg) { return println_native(LOG_ID_MAIN, WARN, tag, msg); } public static int w(String tag, String msg, Throwable tr) { return println_native(LOG_ID_MAIN, WARN, tag, msg + '\n' + getStackTraceString(tr)); } public static int w(String tag, Throwable tr) { return println_native(LOG_ID_MAIN, WARN, tag, getStackTraceString(tr)); } public static int e(String tag, String msg) { return println_native(LOG_ID_MAIN, ERROR, tag, msg); } public static int e(String tag, String msg, Throwable tr) { return println_native(LOG_ID_MAIN, ERROR, tag, msg + '\n' + getStackTraceString(tr)); } .................................................................. /**@hide */ public static native int println_native(int bufID, int priority, String tag, String msg); } to use: private static final String LOG_TAG = "MY_LOG_TAG"; Log.i(LOG_TAG, "This is the log printed by Log.i in android user space."); read log: [email protected]:~/Android$ emulator & [email protected]:~/Android$ adb shell [email protected]:/ # logcat
standalone android emulator 1. download Android SDK 2. mkdir D:\AndroidEmulator 3. mkdir D:\AndroidEmulator\images copy android-sdk-windows\platforms\android-7\images to this dir 4. mkdir D:\AndroidEmulator\skins copy android-sdk-windows\platforms\android-7\skins to this dir. 4. start emulator D:\AndroidEmulator>start /b emulator.exe -sysdir d:\AndroidEmulator -system images\system.img -data images\userdata.img -ramdisk images\ramdisk.img -kernel images\kernel-qemu -skindir d:\AndroidEmulator\skins -skin HVGA
Logger driver kernel/common/drivers/staging/android/logger.h kernel/common/drivers/staging/android/logger.c 1. data structure logger.h: #ifndef _LINUX_LOGGER_H #define _LINUX_LOGGER_H #include <linux/types.h> #include <linux/ioctl.h> struct logger_entry { __u16 len; /* length of the payload */ __u16 __pad; /* no matter what, we get 2 bytes of padding */ __s32 pid; /* generating process's pid */ __s32 tid; /* generating process's tid */ __s32 sec; /* seconds since Epoch */ __s32 nsec; /* nanoseconds */ char msg[0]; /* the entry's payload */ }; #define LOGGER_LOG_RADIO "log_radio" /* radio-related messages */ #define LOGGER_LOG_EVENTS "log_events" /* system/hardware events */ #define LOGGER_LOG_MAIN "log_main" /* everything else */ #define LOGGER_ENTRY_MAX_LEN (4*1024) #define LOGGER_ENTRY_MAX_PAYLOAD \ (LOGGER_ENTRY_MAX_LEN - sizeof(struct logger_entry)) #define __LOGGERIO 0xAE #define LOGGER_GET_LOG_BUF_SIZE _IO(__LOGGERIO, 1) /* size of log */ #define LOGGER_GET_LOG_LEN _IO(__LOGGERIO, 2) /* used log len */ #define LOGGER_GET_NEXT_ENTRY_LEN _IO(__LOGGERIO, 3) /* next entry len */ #define LOGGER_FLUSH_LOG _IO(__LOGGERIO, 4) /* flush log */ #endif /* _LINUX_LOGGER_H */ logger.c: /* * struct logger_log - represents a specific log, such as 'main' or 'radio' * * This structure lives from module insertion until module removal, so it does * not need additional reference counting. The structure is protected by the * mutex 'mutex'. */ struct logger_log { unsigned char * buffer; /* the ring buffer itself */ struct miscdevice misc; /* misc device representing the log */ wait_queue_head_t wq; /* wait queue for readers */ struct list_head readers; /* this log's readers */ struct mutex mutex; /* mutex protecting buffer */ size_t w_off; /* current write head offset */ size_t head; /* new readers start here */ size_t size; /* size of the log */ }; /* * struct logger_reader - a logging device open for reading * * This object lives from open to release, so we don't need additional * reference counting. The structure is protected by log->mutex. */ struct logger_reader { struct logger_log * log; /* associated log */ struct list_head list; /* entry in logger_log's list */ size_t r_off; /* current read head offset */ }; /* logger_offset - returns index 'n' into the log via (optimized) modulus */ #define logger_offset ( & (log->size - 1)) 2.initialization /* * Defines a log structure with name 'NAME' and a size of 'SIZE' bytes, which * must be a power of two, greater than LOGGER_ENTRY_MAX_LEN, and less than * LONG_MAX minus LOGGER_ENTRY_MAX_LEN. */ #define DEFINE_LOGGER_DEVICE(VAR, NAME, SIZE) \ static unsigned char _buf_ ## VAR[SIZE]; \ static struct logger_log VAR = { \ .buffer = _buf_ ## VAR, \ .misc = { \ .minor = MISC_DYNAMIC_MINOR, \ .name = NAME, \ .fops = &logger_fops, \ .parent = NULL, \ }, \ .wq = __WAIT_QUEUE_HEAD_INITIALIZER(VAR .wq), \ .readers = LIST_HEAD_INIT(VAR .readers), \ .mutex = __MUTEX_INITIALIZER(VAR .mutex), \ .w_off = 0, \ .head = 0, \ .size = SIZE, \ }; DEFINE_LOGGER_DEVICE(log_main, LOGGER_LOG_MAIN, 64*1024) DEFINE_LOGGER_DEVICE(log_events, LOGGER_LOG_EVENTS, 256*1024) DEFINE_LOGGER_DEVICE(log_radio, LOGGER_LOG_RADIO, 64*1024) 3. read the log /* * logger_read - our log's read() method * * Behavior: * * - O_NONBLOCK works * - If there are no log entries to read, blocks until log is written to * - Atomically reads exactly one log entry * * Optimal read size is LOGGER_ENTRY_MAX_LEN. Will set errno to EINVAL if read * buffer is insufficient to hold next entry. */ static ssize_t logger_read(struct file *file, char __user *buf, size_t count, loff_t *pos) { struct logger_reader *reader = file->private_data; struct logger_log *log = reader->log; ssize_t ret; DEFINE_WAIT(wait); start: while (1) { prepare_to_wait(&log->wq, &wait, TASK_INTERRUPTIBLE); mutex_lock(&log->mutex); ret = (log->w_off == reader->r_off); mutex_unlock(&log->mutex); if (!ret) break; if (file->f_flags & O_NONBLOCK) { ret = -EAGAIN; break; } if (signal_pending(current)) { ret = -EINTR; break; } schedule(); } finish_wait(&log->wq, &wait); if (ret) return ret; mutex_lock(&log->mutex); /* is there still something to read or did we race? */ if (unlikely(log->w_off == reader->r_off)) { mutex_unlock(&log->mutex); goto start; } /* get the size of the next entry */ ret = get_entry_len(log, reader->r_off); if (count < ret) { ret = -EINVAL; goto out; } /* get exactly one entry from the log */ ret = do_read_log_to_user(log, reader, buf, ret); out: mutex_unlock(&log->mutex); return ret; } 4. write the log /* * logger_aio_write - our write method, implementing support for write(), * writev(), and aio_write(). Writes are our fast path, and we try to optimize * them above all else. */ ssize_t logger_aio_write(struct kiocb *iocb, const struct iovec *iov, unsigned long nr_segs, loff_t ppos) { struct logger_log *log = file_get_log(iocb->ki_filp); size_t orig = log->w_off; struct logger_entry header; struct timespec now; ssize_t ret = 0; now = current_kernel_time(); header.pid = current->tgid; header.tid = current->pid; header.sec = now.tv_sec; header.nsec = now.tv_nsec; header.len = min_t(size_t, iocb->ki_left, LOGGER_ENTRY_MAX_PAYLOAD); /* null writes succeed, return zero */ if (unlikely(!header.len)) return 0; mutex_lock(&log->mutex); /* * Fix up any readers, pulling them forward to the first readable * entry after (what will be) the new write offset. We do this now * because if we partially fail, we can end up with clobbered log * entries that encroach on readable buffer. */ fix_up_readers(log, sizeof(struct logger_entry) + header.len); do_write_log(log, &header, sizeof(struct logger_entry)); while (nr_segs-- > 0) { size_t len; ssize_t nr; /* figure out how much of this vector we can keep */ len = min_t(size_t, iov->iov_len, header.len - ret); /* write out this segment's payload */ nr = do_write_log_from_user(log, iov->iov_base, len); if (unlikely(nr < 0)) { log->w_off = orig; mutex_unlock(&log->mutex); return nr; } iov++; ret += nr; } mutex_unlock(&log->mutex); /* wake up any blocked readers */ wake_up_interruptible(&log->wq); return ret; }
runtime library for the Logger driver 1. log interface for Java ................................................ public final class Log { ................................................ /** * Priority constant for the println method; use Log.v. */ public static final int VERBOSE = 2; /** * Priority constant for the println method; use Log.d. */ public static final int DEBUG = 3; /** * Priority constant for the println method; use Log.i. */ public static final int INFO = 4; /** * Priority constant for the println method; use Log.w. */ public static final int WARN = 5; /** * Priority constant for the println method; use Log.e. */ public static final int ERROR = 6; /** * Priority constant for the println method. */ public static final int ASSERT = 7; ..................................................... public static int v(String tag, String msg) { return println_native(LOG_ID_MAIN, VERBOSE, tag, msg); } public static int v(String tag, String msg, Throwable tr) { return println_native(LOG_ID_MAIN, VERBOSE, tag, msg + '\n' + getStackTraceString(tr)); } public static int d(String tag, String msg) { return println_native(LOG_ID_MAIN, DEBUG, tag, msg); } public static int d(String tag, String msg, Throwable tr) { return println_native(LOG_ID_MAIN, DEBUG, tag, msg + '\n' + getStackTraceString(tr)); } public static int i(String tag, String msg) { return println_native(LOG_ID_MAIN, INFO, tag, msg); } public static int i(String tag, String msg, Throwable tr) { return println_native(LOG_ID_MAIN, INFO, tag, msg + '\n' + getStackTraceString(tr)); } public static int w(String tag, String msg) { return println_native(LOG_ID_MAIN, WARN, tag, msg); } public static int w(String tag, String msg, Throwable tr) { return println_native(LOG_ID_MAIN, WARN, tag, msg + '\n' + getStackTraceString(tr)); } public static int w(String tag, Throwable tr) { return println_native(LOG_ID_MAIN, WARN, tag, getStackTraceString(tr)); } public static int e(String tag, String msg) { return println_native(LOG_ID_MAIN, ERROR, tag, msg); } public static int e(String tag, String msg, Throwable tr) { return println_native(LOG_ID_MAIN, ERROR, tag, msg + '\n' + getStackTraceString(tr)); } .................................................................. /** @hide */ public static native int LOG_ID_MAIN = 0; /** @hide */ public static native int LOG_ID_RADIO = 1; /** @hide */ public static native int LOG_ID_EVENTS = 2; /** @hide */ public static native int LOG_ID_SYSTEM = 3; /** @hide */ public static native int println_native(int bufID, int priority, String tag, String msg); } 2. JNI for logger frameworks/base/core/jni/android_util_Log.cpp /* //device/libs/android_runtime/android_util_Log.cpp ** ** Copyright 2006, 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. */ #define LOG_NAMESPACE "log.tag." #define LOG_TAG "Log_println" #include <assert.h> #include <cutils/properties.h> #include <utils/Log.h> #include <utils/String8.h> #include "jni.h" #include "utils/misc.h" #include "android_runtime/AndroidRuntime.h" #define MIN(a,b) ((a<b)?a:b) namespace android { struct levels_t { jint verbose; jint debug; jint info; jint warn; jint error; jint assert; }; static levels_t levels; static int toLevel(const char* value) { switch (value[0]) { case 'V': return levels.verbose; case 'D': return levels.debug; case 'I': return levels.info; case 'W': return levels.warn; case 'E': return levels.error; case 'A': return levels.assert; case 'S': return -1; // SUPPRESS } return levels.info; } static jboolean android_util_Log_isLoggable(JNIEnv* env, jobject clazz, jstring tag, jint level) { #ifndef HAVE_ANDROID_OS return false; #else /* HAVE_ANDROID_OS */ int len; char key[PROPERTY_KEY_MAX]; char buf[PROPERTY_VALUE_MAX]; if (tag == NULL) { return false; } jboolean result = false; const char* chars = env->GetStringUTFChars(tag, NULL); if ((strlen(chars)+sizeof(LOG_NAMESPACE)) > PROPERTY_KEY_MAX) { jclass clazz = env->FindClass("java/lang/IllegalArgumentException"); char buf2[200]; snprintf(buf2, sizeof(buf2), "Log tag \"%s\" exceeds limit of %d characters\n", chars, PROPERTY_KEY_MAX - sizeof(LOG_NAMESPACE)); // release the chars! env->ReleaseStringUTFChars(tag, chars); env->ThrowNew(clazz, buf2); return false; } else { strncpy(key, LOG_NAMESPACE, sizeof(LOG_NAMESPACE)-1); strcpy(key + sizeof(LOG_NAMESPACE) - 1, chars); } env->ReleaseStringUTFChars(tag, chars); len = property_get(key, buf, ""); int logLevel = toLevel(buf); return (logLevel >= 0 && level >= logLevel) ? true : false; #endif /* HAVE_ANDROID_OS */ } /* * In class android.util.Log: * public static native int println_native(int buffer, int priority, String tag, String msg) */ static jint android_util_Log_println_native(JNIEnv* env, jobject clazz, jint bufID, jint priority, jstring tagObj, jstring msgObj) { const char* tag = NULL; const char* msg = NULL; if (msgObj == NULL) { jclass npeClazz; npeClazz = env->FindClass("java/lang/NullPointerException"); assert(npeClazz != NULL); env->ThrowNew(npeClazz, "println needs a message"); return -1; } if (bufID < 0 || bufID >= LOG_ID_MAX) { jclass npeClazz; npeClazz = env->FindClass("java/lang/NullPointerException"); assert(npeClazz != NULL); env->ThrowNew(npeClazz, "bad bufID"); return -1; } if (tagObj != NULL) tag = env->GetStringUTFChars(tagObj, NULL); msg = env->GetStringUTFChars(msgObj, NULL); int res = __android_log_buf_write(bufID, (android_LogPriority)priority, tag, msg); if (tag != NULL) env->ReleaseStringUTFChars(tagObj, tag); env->ReleaseStringUTFChars(msgObj, msg); return res; } /* * JNI registration. */ static JNINativeMethod gMethods[] = { /* name, signature, funcPtr */ { "isLoggable", "(Ljava/lang/String;I)Z", (void*) android_util_Log_isLoggable }, { "println_native", "(IILjava/lang/String;Ljava/lang/StringI", (void*) android_util_Log_println_native }, }; int register_android_util_Log(JNIEnv* env) { jclass clazz = env->FindClass("android/util/Log"); if (clazz == NULL) { LOGE("Can't find android/util/Log"); return -1; } levels.verbose = env->GetStaticIntField(clazz, env->GetStaticFieldID(clazz, "VERBOSE", "I")); levels.debug = env->GetStaticIntField(clazz, env->GetStaticFieldID(clazz, "DEBUG", "I")); levels.info = env->GetStaticIntField(clazz, env->GetStaticFieldID(clazz, "INFO", "I")); levels.warn = env->GetStaticIntField(clazz, env->GetStaticFieldID(clazz, "WARN", "I")); levels.error = env->GetStaticIntField(clazz, env->GetStaticFieldID(clazz, "ERROR", "I")); levels.assert = env->GetStaticIntField(clazz, env->GetStaticFieldID(clazz, "ASSERT", "I")); return AndroidRuntime::registerNativeMethods(env, "android/util/Log", gMethods, NELEM(gMethods)); } }; // namespace android 3. runtime library liblog int __android_log_buf_write(int bufID, int prio, const char *tag, const char *msg) { struct iovec vec[3]; if (!tag) tag = ""; /* XXX: This needs to go! */ if (!strcmp(tag, "HTC_RIL") || !strncmp(tag, "RIL", 3) || /* Any log tag with "RIL" as the prefix */ !strcmp(tag, "AT") || !strcmp(tag, "GSM") || !strcmp(tag, "STK") || !strcmp(tag, "CDMA") || !strcmp(tag, "PHONE") || !strcmp(tag, "SMS")) bufID = LOG_ID_RADIO; vec[0].iov_base = (unsigned char *) &prio; vec[0].iov_len = 1; vec[1].iov_base = (void *) tag; vec[1].iov_len = strlen(tag) + 1; vec[2].iov_base = (void *) msg; vec[2].iov_len = strlen(msg) + 1; return write_to_log(bufID, vec, 3); } static int __write_to_log_init(log_id_t, struct iovec *vec, size_t nr); static int (*write_to_log)(log_id_t, struct iovec *vec, size_t nr) = __write_to_log_init; static int __write_to_log_init(log_id_t log_id, struct iovec *vec, size_t nr) { #ifdef HAVE_PTHREADS pthread_mutex_lock(&log_init_lock); #endif if (write_to_log == __write_to_log_init) { log_fds[LOG_ID_MAIN] = log_open("/dev/"LOGGER_LOG_MAIN, O_WRONLY); log_fds[LOG_ID_RADIO] = log_open("/dev/"LOGGER_LOG_RADIO, O_WRONLY); log_fds[LOG_ID_EVENTS] = log_open("/dev/"LOGGER_LOG_EVENTS, O_WRONLY); log_fds[LOG_ID_SYSTEM] = log_open("/dev/"LOGGER_LOG_SYSTEM, O_WRONLY); write_to_log = __write_to_log_kernel; if (log_fds[LOG_ID_MAIN] < 0 || log_fds[LOG_ID_RADIO] < 0 || log_fds[LOG_ID_EVENTS] < 0) { log_close(log_fds[LOG_ID_MAIN]); log_close(log_fds[LOG_ID_RADIO]); log_close(log_fds[LOG_ID_EVENTS]); log_fds[LOG_ID_MAIN] = -1; log_fds[LOG_ID_RADIO] = -1; log_fds[LOG_ID_EVENTS] = -1; write_to_log = __write_to_log_null; } if (log_fds[LOG_ID_SYSTEM] < 0) { log_fds[LOG_ID_SYSTEM] = log_fds[LOG_ID_MAIN]; } } #ifdef HAVE_PTHREADS pthread_mutex_unlock(&log_init_lock); #endif return write_to_log(log_id, vec, nr); } ...
Logcat tool system/core/logcat 1. data structure struct queued_entry_t { union { unsigned char buf[LOGGER_ENTRY_MAX_LEN + 1] __attribute__((aligned(4))); struct logger_entry entry __attribute__((aligned(4))); }; queued_entry_t* next; queued_entry_t() { next = NULL; } }; struct log_device_t { char* device; bool binary; int fd; bool printed; char label; queued_entry_t* queue; log_device_t* next; log_device_t(char* d, bool b, char l) { device = d; binary = b; label = l; queue = NULL; next = NULL; printed = false; } void enqueue(queued_entry_t* entry) { if (this->queue == NULL) { this->queue = entry; } else { queued_entry_t** e = &this->queue; while (*e && cmp(entry, *e) >= 0) { e = &((*e)->next); } entry->next = *e; *e = entry; } } }; 2. initialization static void setupOutput() { if (g_outputFileName == NULL) { g_outFD = STDOUT_FILENO; } else { struct stat statbuf; g_outFD = openLogFile (g_outputFileName); if (g_outFD < 0) { perror ("couldn't open output file"); exit(-1); } fstat(g_outFD, &statbuf); g_outByteCount = statbuf.st_size; } } dev = devices; while (dev) { dev->fd = open(dev->device, mode); if (dev->fd < 0) { fprintf(stderr, "Unable to open log device '%s': %s\n", dev->device, strerror(errno)); exit(EXIT_FAILURE); } if (clearLog) { int ret; ret = android::clearLog(dev->fd); if (ret) { perror("ioctl"); exit(EXIT_FAILURE); } } if (getLogSize) { int size, readable; size = android::getLogSize(dev->fd); if (size < 0) { perror("ioctl"); exit(EXIT_FAILURE); } readable = android::getLogReadableSize(dev->fd); if (readable < 0) { perror("ioctl"); exit(EXIT_FAILURE); } printf("%s: ring buffer is %dKb (%dKb consumed), " "max entry is %db, max payload is %db\n", dev->device, size / 1024, readable / 1024, (int) LOGGER_ENTRY_MAX_LEN, (int) LOGGER_ENTRY_MAX_PAYLOAD); } dev = dev->next; } 3. read the log static void readLogLines(log_device_t* devices) { log_device_t* dev; int max = 0; int ret; int queued_lines = 0; bool sleep = true; int result; fd_set readset; for (dev=devices; dev; dev = dev->next) { if (dev->fd > max) { max = dev->fd; } } while (1) { do { timeval timeout = { 0, 5000 /* 5ms */ }; // If we oversleep it's ok, i.e. ignore EINTR. FD_ZERO(&readset); for (dev=devices; dev; dev = dev->next) { FD_SET(dev->fd, &readset); } result = select(max + 1, &readset, NULL, NULL, sleep ? NULL : &timeout); } while (result == -1 && errno == EINTR); if (result >= 0) { for (dev=devices; dev; dev = dev->next) { if (FD_ISSET(dev->fd, &readset)) { queued_entry_t* entry = new queued_entry_t(); /* NOTE: driver guarantees we read exactly one full entry */ ret = read(dev->fd, entry->buf, LOGGER_ENTRY_MAX_LEN); if (ret < 0) { if (errno == EINTR) { delete entry; goto next; } if (errno == EAGAIN) { delete entry; break; } perror("logcat read"); exit(EXIT_FAILURE); } else if (!ret) { fprintf(stderr, "read: Unexpected EOF!\n"); exit(EXIT_FAILURE); } entry->entry.msg[entry->entry.len] = '\0'; dev->enqueue(entry); ++queued_lines; } } if (result == 0) { // we did our short timeout trick and there's nothing new // print everything we have and wait for more data sleep = true; while (true) { chooseFirst(devices, &dev); if (dev == NULL) { break; } if (g_tail_lines == 0 || queued_lines <= g_tail_lines) { printNextEntry(dev); } else { skipNextEntry(dev); } --queued_lines; } // the caller requested to just dump the log and exit if (g_nonblock) { exit(0); } } else { // print all that aren't the last in their list sleep = false; while (g_tail_lines == 0 || queued_lines > g_tail_lines) { chooseFirst(devices, &dev); if (dev == NULL || dev->queue->next == NULL) { break; } if (g_tail_lines == 0) { printNextEntry(dev); } else { skipNextEntry(dev); } --queued_lines; } } } next: ; } } 4. output the log static void printNextEntry(log_device_t* dev) { maybePrintStart(dev); if (g_printBinary) { printBinary(&dev->queue->entry); } else { processBuffer(dev, &dev->queue->entry); } skipNextEntry(dev); } void printBinary(struct logger_entry *buf) { size_t size = sizeof(logger_entry) + buf->len; int ret; do { ret = write(g_outFD, buf, size); } while (ret < 0 && errno == EINTR); } ...
Binder driver
start of Service Manager frameworks/base/cmds/servicemanager service_manager.c int main(int argc, char **argv) { struct binder_state *bs; void *svcmgr = BINDER_SERVICE_MANAGER; bs = binder_open(128*1024); if (binder_become_context_manager(bs)) { LOGE("cannot become context manager (%s)\n", strerror(errno)); return -1; } svcmgr_handle = svcmgr; binder_loop(bs, svcmgr_handler); return 0; } frameworks/base/cmds/servicemanager/binder.c struct binder_state { int fd; void *mapped; unsigned mapsize; }; frameworks/base/cmds/servicemanager/binder.h /* the one magic object */ #define BINDER_SERVICE_MANAGER ((void*) 0) frameworks/base/cmds/servicemanager/binder.c struct binder_state *binder_open(unsigned mapsize) { struct binder_state *bs; bs = malloc(sizeof(*bs)); if (!bs) { errno = ENOMEM; return 0; } bs->fd = open("/dev/binder", O_RDWR); if (bs->fd < 0) { fprintf(stderr,"binder: cannot open device (%s)\n", strerror(errno)); goto fail_open; } bs->mapsize = mapsize; bs->mapped = mmap(NULL, mapsize, PROT_READ, MAP_PRIVATE, bs->fd, 0); if (bs->mapped == MAP_FAILED) { fprintf(stderr,"binder: cannot map device (%s)\n", strerror(errno)); goto fail_map; } /* TODO: check version */ return bs; fail_map: close(bs->fd); fail_open: free(bs); return 0; } kernel/common/drivers/staging/android binder.c static struct file_operations binder_fops = { .owner = THIS_MODULE, .poll = binder_poll, .unlocked_ioctl = binder_ioctl, .mmap = binder_mmap, .open = binder_open, .flush = binder_flush, .release = binder_release, }; static struct miscdevice binder_miscdev = { .minor = MISC_DYNAMIC_MINOR, .name = "binder", .fops = &binder_fops }; static int __init binder_init(void) { int ret; binder_proc_dir_entry_root = proc_mkdir("binder", NULL); if (binder_proc_dir_entry_root) binder_proc_dir_entry_proc = proc_mkdir("proc", binder_proc_dir_entry_root); ret = misc_register(&binder_miscdev); if (binder_proc_dir_entry_root) { create_proc_read_entry("state", S_IRUGO, binder_proc_dir_entry_root, binder_read_proc_state, NULL); create_proc_read_entry("stats", S_IRUGO, binder_proc_dir_entry_root, binder_read_proc_stats, NULL); create_proc_read_entry("transactions", S_IRUGO, binder_proc_dir_entry_root, binder_read_proc_transactions, NULL); create_proc_read_entry("transaction_log", S_IRUGO, binder_proc_dir_entry_root, binder_read_proc_transaction_log, &binder_transaction_log); create_proc_read_entry("failed_transaction_log", S_IRUGO, binder_proc_dir_entry_root, binder_read_proc_transaction_log, &binder_transaction_log_failed); } return ret; } device_initcall(binder_init); ...
getting the Service Manager proxy frameworks/base/include/binder/IServiceManager.h sp<IServiceManager> defaultServiceManager(); frameworks/base/libs/binder/IServiceManager.cpp sp<IServiceManager> defaultServiceManager() { if (gDefaultServiceManager != NULL) return gDefaultServiceManager; { AutoMutex _l(gDefaultServiceManagerLock); if (gDefaultServiceManager == NULL) { gDefaultServiceManager = interface_cast<IServiceManager>( ProcessState::self()->getContextObject(NULL)); } } return gDefaultServiceManager; } frameworks/base/libs/binder/Static.cpp Mutex gDefaultServiceManagerLock; sp<IServiceManager> gDefaultServiceManager; class map frameworks/base/include/binder/IInterface.h template<typename INTERFACE> class BpInterface : public INTERFACE, public BpRefBase { public: BpInterface(const sp<IBinder>& remote); protected: virtual IBinder* onAsBinder(); }; ...
start of Service MediaPlayerService class map frameworks/base/include/binder/IInterface.h template<typename INTERFACE> class BnInterface : public INTERFACE, public BBinder { public: virtual sp<IInterface> queryLocalInterface(const String16& _descriptor); virtual const String16& getInterfaceDescriptor() const; protected: virtual IBinder* onAsBinder(); }; frameworks/base/media/mediaserver/main_mediaserver.cpp int main(int argc, char** argv) { sp<ProcessState> proc(ProcessState::self()); sp<IServiceManager> sm = defaultServiceManager(); LOGI("ServiceManager: %p", sm.get()); AudioFlinger::instantiate(); MediaPlayerService::instantiate(); CameraService::instantiate(); AudioPolicyService::instantiate(); ProcessState::self()->startThreadPool(); IPCThreadState::self()->joinThreadPool(); } interaction
[Q] Building Nyandroid + platlogo into an app
I've been hacking away at a few java files (PlatlogoActivity.java, Nyandroid.java) extracted from AOSP ICS source in Eclipse. There were some errors that I was able to solve (some funky ones about vibration, but I just removed all code related to vibration instead) but now there is one error, that no matter what, I can't solve. In the Nyandroid.java, I keep on getting the error "Cannot cast from TimeAnimator to ValueAnimator" on the line "((ValueAnimator) mAnim).cancel();" no matter how much I try changing that line (for example to "mAnim.cancel();") based on some custom ROM sources that I've looked through, and some stackoverflow questions. The app source is attached to this post, and below you can find the Nyandroid.java if you're willing to help - please do. I want to get into app developing for Android, or atleast understanding some java. I managed to port the Gingerbread platlogo for all Android versions but it's obviously much easier to do because it's just one still image and a toast. But I really want to port the ICS Nyandroid easter egg, for some practice with java. /*); * Copyright (C) 2011 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. */ package com.android.nyandroid; import android.animation.AnimatorSet; import android.animation.PropertyValuesHolder; import android.animation.ObjectAnimator; import android.animation.TimeAnimator; import android.animation.ValueAnimator; import android.app.Activity; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.graphics.drawable.AnimationDrawable; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Matrix; import android.graphics.Paint; import android.graphics.Point; import android.graphics.Rect; import android.graphics.RectF; import android.os.Handler; import android.util.AttributeSet; import android.util.DisplayMetrics; import android.util.Pair; import android.view.Gravity; import android.view.MotionEvent; import android.view.View; import android.view.ViewGroup; import android.view.WindowManager; import android.widget.FrameLayout; import android.widget.ImageView; import java.util.HashMap; import java.util.Random; public class Nyandroid extends Activity { final static boolean DEBUG = false; public static class Board extends FrameLayout { public static final boolean FIXED_STARS = true; public static final int NUM_CATS = 20; static Random sRNG = new Random(); static float lerp(float a, float b, float f) { return (b-a)*f + a; } static float randfrange(float a, float b) { return lerp(a, b, sRNG.nextFloat()); } static int randsign() { return sRNG.nextBoolean() ? 1 : -1; } static <E> E pick(E[] array) { if (array.length == 0) return null; return array[sRNG.nextInt(array.length)]; } public class FlyingCat extends ImageView { public static final float VMAX = 1000.0f; public static final float VMIN = 100.0f; public float v, vr; public float dist; public float z; public ComponentName component; public FlyingCat(Context context, AttributeSet as) { super(context, as); setImageResource(R.drawable.nyandroid_anim); // @@@ if (DEBUG) setBackgroundColor(0x80FF0000); } public String toString() { return String.format("<cat (%.1f, %.1f) (%d x %d)>", getX(), getY(), getWidth(), getHeight()); } public void reset() { final float scale = lerp(0.1f,2f,z); setScaleX(scale); setScaleY(scale); setX(-scale*getWidth()+1); setY(randfrange(0, Board.this.getHeight()-scale*getHeight())); v = lerp(VMIN, VMAX, z); dist = 0; // android.util.Log.d("Nyandroid", "reset cat: " + this); } public void update(float dt) { dist += v * dt; setX(getX() + v * dt); } } TimeAnimator mAnim; public Board(Context context, AttributeSet as) { super(context, as); setLayerType(View.LAYER_TYPE_HARDWARE, null); setSystemUiVisibility(View.SYSTEM_UI_FLAG_LOW_PROFILE | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION); setBackgroundColor(0xFF003366); } private void reset() { // android.util.Log.d("Nyandroid", "board reset"); removeAllViews(); final ViewGroup.LayoutParams wrap = new ViewGroup.LayoutParams( ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT); if (FIXED_STARS) { for(int i=0; i<20; i++) { ImageView fixedStar = new ImageView(getContext(), null); if (DEBUG) fixedStar.setBackgroundColor(0x8000FF80); fixedStar.setImageResource(R.drawable.star_anim); // @@@ addView(fixedStar, wrap); final float scale = randfrange(0.1f, 1f); fixedStar.setScaleX(scale); fixedStar.setScaleY(scale); fixedStar.setX(randfrange(0, getWidth())); fixedStar.setY(randfrange(0, getHeight())); final AnimationDrawable anim = (AnimationDrawable) fixedStar.getDrawable(); postDelayed(new Runnable() { public void run() { anim.start(); }}, (int) randfrange(0, 1000)); } } for(int i=0; i<NUM_CATS; i++) { FlyingCat nv = new FlyingCat(getContext(), null); addView(nv, wrap); nv.z = ((float)i/NUM_CATS); nv.z *= nv.z; nv.reset(); nv.setX(randfrange(0,Board.this.getWidth())); final AnimationDrawable anim = (AnimationDrawable) nv.getDrawable(); postDelayed(new Runnable() { public void run() { anim.start(); }}, (int) randfrange(0, 1000)); } if (mAnim != null) { ((ValueAnimator) mAnim).cancel(); } mAnim = new TimeAnimator(); mAnim.setTimeListener(new TimeAnimator.TimeListener() { public void onTimeUpdate(TimeAnimator animation, long totalTime, long deltaTime) { // setRotation(totalTime * 0.01f); // not as cool as you would think // android.util.Log.d("Nyandroid", "t=" + totalTime); for (int i=0; i<getChildCount(); i++) { View v = getChildAt(i); if (!(v instanceof FlyingCat)) continue; FlyingCat nv = (FlyingCat) v; nv.update(deltaTime / 1000f); final float catWidth = nv.getWidth() * nv.getScaleX(); final float catHeight = nv.getHeight() * nv.getScaleY(); if ( nv.getX() + catWidth < -2 || nv.getX() > getWidth() + 2 || nv.getY() + catHeight < -2 || nv.getY() > getHeight() + 2) { nv.reset(); } } } }); } @Override protected void onSizeChanged (int w, int h, int oldw, int oldh) { super.onSizeChanged(w,h,oldw,oldh); // android.util.Log.d("Nyandroid", "resized: " + w + "x" + h); post(new Runnable() { public void run() { reset(); mAnim.start(); } }); } @Override protected void onDetachedFromWindow() { super.onDetachedFromWindow(); mAnim.cancel(); } @Override public boolean isOpaque() { return true; } } private Board mBoard; @Override public void onStart() { super.onStart(); getWindow().addFlags( WindowManager.LayoutParams.FLAG_ALLOW_LOCK_WHILE_SCREEN_ON | WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED ); } @Override public void onResume() { super.onResume(); mBoard = new Board(this, null); setContentView(mBoard); mBoard.setOnSystemUiVisibilityChangeListener(new View.OnSystemUiVisibilityChangeListener() { @Override public void onSystemUiVisibilityChange(int vis) { if (0 == (vis & View.SYSTEM_UI_FLAG_HIDE_NAVIGATION)) { Nyandroid.this.finish(); } } }); } @Override public void onUserInteraction() { // android.util.Log.d("Nyandroid", "finishing on user interaction"); finish(); } } Click to expand... Click to collapse
[Q] Android: Why are my images coming in so blurry?
I have a Slideshow for the Home Page of my app looks sorta like the Houzz apps Home Page, were it displays a new image daily. But their is one issue I am having is that all of my images are coming in so blurry. I've checked the Resolution and it shouldn't be that blurry for no reason at all. I've tried changing setScaleType such as switching it too CENTER, CENTER_CROP, and Etc... None of those seemed to work. I have tried everything too my knowledge and now I am stuck, Below are some of my relevant source code in order too successfully help me out on this issue. This is the Home.java this is linked/runs functions of homebck.xml: Code: public class Home extends Fragment { private final int FileUpload = 100; public static final String URL = private Context context; private ImageView m_imageInformation; private ImageView m_imageSave; private ImageView m_imageWallPaper; private ViewPager m_viewPager; private ImageAdapter m_imageAdapter; private ArrayList<ImageView> m_imageViewList; private int[] m_galleryImages = new int[]{ R.drawable.ic_share, R.drawable.ic_share, R.drawable.ic_share }; public static String popup_status = ""; public static File path = new File(Environment.getExternalStorageDirectory() + ""); public static Item[] fileList; public static String chosenFile; public static Boolean firstLvl = true; ListAdapter adapter; public static ArrayList<String> str = new ArrayList<String>(); public String dbPath = "/data/data/com.Celebration/"; private AboutPopup m_aboutPopup; private InformationPopup m_informationPopup; public static String ss; public static List<DBManager.ImageModel> m_images; public ImageLoader imageLoader; @Override public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { // return super.onCreateView(inflater, container, savedInstanceState); // super.onCreateView(inflater, container, savedInstanceState); context = getActivity(); View rootView = inflater.inflate(R.layout.homebck, container, false); m_viewPager = (ViewPager) rootView.findViewById(R.id.view_pager); m_imageInformation = (ImageView) rootView.findViewById(R.id.image_information); m_imageSave = (ImageView) rootView.findViewById(R.id.image_save); m_imageWallPaper = (ImageView) rootView.findViewById(R.id.image_wallpaper); initView(); m_imageInformation.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Globals.imageNumber = m_viewPager.getCurrentItem(); m_informationPopup.showAtLocation(m_viewPager, 0, 0); } }); m_imageSave.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { loadFileList(); onCreateDialog(100); } }); m_imageWallPaper.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Intent sendIntent = new Intent(); sendIntent.setAction(Intent.ACTION_SEND); //sendIntent.setAction(Intent.ACTION_CHOOSER); sendIntent.putExtra(Intent.EXTRA_SUBJECT, ""); sendIntent.putExtra(Intent.EXTRA_EMAIL, ""); sendIntent.setType("text/plain"); sendIntent.putExtra(Intent.EXTRA_TEXT, "Hello, I wanted to invite you to join this app with me! It's a guide about Celebration, FL. Come see "); sendIntent.setType("text/plain"); //Sipdroid.this.startActivity(sendIntent);*/ context.startActivity(Intent.createChooser(sendIntent, "Tell a friend via...")); } }); return rootView; } public void initView(){ m_imageViewList = new ArrayList<ImageView>(); m_aboutPopup = new AboutPopup(getActivity()); m_informationPopup = new InformationPopup(getActivity()); Globals.m_dbMan = new DBManager(context); m_images = Globals.m_dbMan.getImageListData(); m_imageViewList.clear(); if(m_images != null){ for (int i = m_images.size() - 1 ; i >= 0; i--) { ImageView imageView = new ImageView(context); setImage(imageView, i); m_imageViewList.add(imageView); } }else{ ImageView imageView = new ImageView(context); imageLoader = new ImageLoader(context); imageLoader.DisplayImage(URL, imageView); imageView.setScaleType(ImageView.ScaleType.FIT_XY); m_imageViewList.add(imageView); } m_imageAdapter = new ImageAdapter(m_imageViewList); m_viewPager.setAdapter(m_imageAdapter); } public void setImage(ImageView m_imgView, int currentIndex) { File imgFile = new File(m_images.get(currentIndex).imagePath); //Uri uri = Uri.fromFile(new File(lstImage.get(currentIndex).imagePath)); Bitmap myBitmap = decodeFile(imgFile); m_imgView.setImageBitmap(myBitmap); m_imgView.setAdjustViewBounds(true); m_imgView.setScaleType(ImageView.ScaleType.CENTER_INSIDE); } public static Bitmap decodeFile(File f){ Bitmap b = null; int IMAGE_MAX_SIZE = 1000; //Decode image size BitmapFactory.Options o = new BitmapFactory.Options(); o.inJustDecodeBounds = true; FileInputStream fis; try { fis = new FileInputStream(f); BitmapFactory.decodeStream(fis, null, o); try { fis.close(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } int scale = 1; if (o.outHeight > IMAGE_MAX_SIZE || o.outWidth > IMAGE_MAX_SIZE) { int maxwh = Math.max(o.outWidth,o.outHeight); while(maxwh / scale > IMAGE_MAX_SIZE) scale *= 2; } Log.d("twinklestar.containerrecog", "width: " + o.outWidth + "height: " + o.outHeight + "scale:" + scale); //Decode with inSampleSize BitmapFactory.Options o2 = new BitmapFactory.Options(); o2.inSampleSize = scale; fis = new FileInputStream(f); b = BitmapFactory.decodeStream(fis, null, o2); try { fis.close(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } catch (FileNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); } return b; } /* @Override public void onClick(View v) { Log.d("onclick", "ok"); switch (v.getId()){ case R.id.image_information: { Toast.makeText(context, "ok", Toast.LENGTH_SHORT).show(); break; } case R.id.image_save: { // loadFileList(); onCreateDialog(100); break; } case R.id.image_wallpaper: { ((Activity)context).finish(); break; } default: break; } }*/ protected Dialog onCreateDialog(int id) { Dialog dialog = null; AlertDialog.Builder builder = new AlertDialog.Builder(this.getActivity()); if (fileList == null) { Log.e("TAG", "No files loaded"); dialog = builder.create(); return dialog; } switch (id) { case FileUpload: builder.setTitle("Select a Folder to save"); builder.setPositiveButton("download", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) { // continue with delete ImageView image = new ImageView(context); imageLoader = new ImageLoader(context); Globals.downloadFlag = true; Globals.downlaodForSaving = true; Globals.saveFolder = path.toString(); imageLoader.DisplayImage(URL, image); } }); builder.setNegativeButton("cancel", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) { // do nothing } }); builder.setAdapter(adapter, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { chosenFile = fileList[which].file; File sel = new File(path + "/" + chosenFile); if (sel.isDirectory()) { firstLvl = false; // Adds chosen directory to list str.add(chosenFile); fileList = null; path = new File(sel + ""); loadFileList(); dialog.dismiss(); onCreateDialog(FileUpload); Log.d("TAG", path.getAbsolutePath()); } // Checks if 'up' was clicked else if (chosenFile.equalsIgnoreCase("up") && !sel.exists()) { // present directory removed from list String s = str.remove(str.size() - 1); // path modified to exclude present directory path = new File(path.toString().substring(0, path.toString().lastIndexOf(s))); fileList = null; // if there are no more directories in the list, then // its the first level if (str.isEmpty()) { firstLvl = true; } loadFileList(); //UploadFragment.this.getActivity().removeDialog(DIALOG_LOAD_FILE); dialog.dismiss(); onCreateDialog(FileUpload); //UploadFragment.this.getActivity().showDialog(DIALOG_LOAD_FILE); Log.d("TAG", path.getAbsolutePath()); } // File picked else { // Perform action with file picked //Toast.makeText(UploadFragment.this.getActivity(), chosenFile, Toast.LENGTH_SHORT).show(); ss = path.getAbsolutePath() + "/" + chosenFile; String extension = chosenFile.substring(chosenFile.indexOf(".") + 1); if (extension.equals("png") || extension.equals("jpg") || extension.equals("bmp")) { dialog.dismiss(); m_aboutPopup.showAtLocation(m_viewPager, 0, 0); // onUpload(ss,chosenFile); } else Toast.makeText(getActivity(), "This is not image file!", Toast.LENGTH_SHORT).show(); } } }); break; } dialog = builder.show(); return dialog; } Below this a SNIPPET/part of the MainActivity.java *hint URL1,2,3,4... Grabs the URL that is put into String: Code: public static String des; public String myurl = null; public class AboutPopup implements View.OnClickListener { public View parent; public PopupWindow popupWindow; public ListView m_listHolder; public EditText m_editDescription; public Button m_btnUpload; public DatePicker dp; public TimePicker tp; private PendingIntent pendingIntent; private Spinner spinner; private ImageView imageView; private TextView selectImageurl; private TextView imageDescription; public AboutPopup(Context paramContext) { this.parent = ((LayoutInflater) paramContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE)).inflate(R.layout.settting_popup, null); //this.parent.findViewBy) this.popupWindow = new PopupWindow(this.parent, ViewGroup.LayoutParams.FILL_PARENT, ViewGroup.LayoutParams.FILL_PARENT, true); this.m_editDescription = (EditText) parent.findViewById(R.id.setting_description); this.m_btnUpload = (Button) parent.findViewById(R.id.btn_setting_show); m_btnUpload.setOnClickListener(this); selectImageurl = (TextView) parent.findViewById(R.id.select_imageurl); imageDescription = (TextView) parent.findViewById(R.id.image_description); selectImageurl.setTextSize(convertFromDp(24)); imageDescription.setTextSize(convertFromDp(24)); dp = (DatePicker) parent.findViewById(R.id.datePicker); tp = (TimePicker) parent.findViewById(R.id.timePicker); dp.setCalendarViewShown(false); imageView = (ImageView)parent.findViewById(R.id.setting_image); spinner = (Spinner) parent.findViewById(R.id.setting_spinner); String[] platforms = paramContext.getResources(). getStringArray(R.array.dev_platforms); ArrayAdapter<String> adapter = new ArrayAdapter<String>(paramContext, R.layout.spinner_item, platforms); spinner.setAdapter(adapter); // If you want to continue on that TimeDateActivity // If you want to go to new activity that code you can also write here spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() { @Override public void onItemSelected(AdapterView<?> parent, View view, int position, long id) { switch(position){ case 0: myurl = URL; break; case 1: myurl = URL1; break; case 2: myurl = URL3; break; case 3: myurl = URL4; break; case 4: break; } if(myurl != null){ imageLoader = new ImageLoader(MainActivity.this); imageLoader.DisplayImage(myurl, imageView); } } @Override public void onNothingSelected(AdapterView<?> parent) { } }); } public void showAtLocation(View pView, int left, int top) { this.popupWindow.setOutsideTouchable(true); this.popupWindow.setTouchable(true); this.popupWindow.update(); popupWindow.setBackgroundDrawable(new BitmapDrawable()); popupWindow.setAnimationStyle(R.style.PopupAnimation); popupWindow.setWidth((int) (pView.getWidth() * 0.95)); popupWindow.setHeight((int) (pView.getHeight())); popupWindow.showAtLocation(pView, Gravity.CENTER_VERTICAL, 0, 0); // this.popupWindow.showAtLocation(pView, Gravity.CENTER, left, top); } public void hide() { this.popupWindow.dismiss(); } public boolean isVisible() { return this.popupWindow.isShowing(); } @Override public void onClick(View view) { switch (view.getId()) { case R.id.btn_setting_show: { imageLoader = new ImageLoader(MainActivity.this); Globals.downloadFlag = true; imageLoader.DisplayImage(myurl, imageView); ss = path.getAbsolutePath() + "/" + ImageLoader.fname; des = this.m_editDescription.getText().toString(); Globals.alarmFileName[Globals.alarmNumber] = ImageLoader.fname; Globals.alarmDescription[Globals.alarmNumber] = des; Globals.alarmNumber = Globals.alarmNumber + 1; String strDateTime = dp.getYear() + "-" + (dp.getMonth() + 1) + "-" + dp.getDayOfMonth(); Intent Intent = new Intent(MainActivity.this, AlarmReceiver.class); Intent.putExtra("id",Globals.alarmNumber-1); pendingIntent = PendingIntent.getBroadcast(MainActivity.this, 0, Intent, 0); Calendar cal = Calendar.getInstance(); cal.set(dp.getYear(), dp.getMonth(), dp.getDayOfMonth(),tp.getCurrentHour(), tp.getCurrentMinute()); Calendar current = Calendar.getInstance(); if(current.get(Calendar.YEAR) > cal.get(Calendar.YEAR) && current.get(Calendar.MONTH) > cal.get(Calendar.MONTH) && current.get(Calendar.DATE) > cal.get(Calendar.DATE)){ Toast.makeText(MainActivity.this, "Please select other time", Toast.LENGTH_SHORT).show(); return; } // schedule for every 30 seconds alarm.set(AlarmManager.RTC_WAKEUP, cal.getTimeInMillis(), pendingIntent); if (des == null) { Toast.makeText(MainActivity.this, "Input description in..", Toast.LENGTH_SHORT).show(); return; } else { popupWindow.dismiss(); } } break; } } } homebck.xml: Code: <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="..." android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:id="@+id/homefragment" android:background="@color/white"> <android.support.v4.view.ViewPager android:id="@+id/view_pager" android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="10" /> <LinearLayout android:orientation="horizontal" android:layout_width="match_parent" android:layout_height="0dp" android:layout_gravity="center_horizontal" android:layout_weight="1"> <ImageView android:id="@+id/image_information" android:layout_width="0dp" android:layout_height="match_parent" android:src="@drawable/ic_information" android:layout_weight="1" /> <ImageView android:id="@+id/image_save" android:layout_width="0dp" android:layout_height="match_parent" android:src="@drawable/ic_save" android:layout_weight="1" /> <ImageView android:id="@+id/image_wallpaper" android:layout_width="0dp" android:layout_height="match_parent" android:src="@drawable/ic_share" android:layout_weight="1"/> </LinearLayout> </LinearLayout>
How to crop bitmaps according to size of a custom view
Trying to make a motion detection app. The intention is to make the app take pictures when motion is detected by comparing two images. Up to this part, the app is working fine. Requirement: To specify area of detection by a custom view. So that, the pictures will be captured only if a motion is detected inside the defined area by calculating the detection area. What I have tried: Created a movable custom view, like a crop view of which the dimensions (`Rect`) are saved in the preference each time when the view is moved. In the detection thread I tried setting the width and height from the preference like Code: private int width = Prefe.DetectionArea.width(); private int height = Prefe.DetectionArea.height(); But it didn't work. What is not working: The motion detection from inside the custom view is not working. I believe that the bitmaps must be cropped according to the size of the custom view. Please help me by explaining how this could be achieved so that the motion detection will happen according to the size of the custom view. I'm new to android and trying to self learn, any help is appreciated. MotionDetectionActivity.java Code: public class MotionDetectionActivity extends SensorsActivity { private static final String TAG = "MotionDetectionActivity"; private static long mReferenceTime = 0; private static IMotionDetection detector = null; public static MediaPlayer song; public static Vibrator mVibrator; private static SurfaceView preview = null; private static SurfaceHolder previewHolder = null; private static Camera camera = null; private static boolean inPreview = false; private static AreaDetectorView mDetector; private static FrameLayout layoutDetectorArea; static FrameLayout layoutMain; static View mView; private static volatile AtomicBoolean processing = new AtomicBoolean(false); /** * {@inheritDoc} */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); setContentView(R.layout.main); mVibrator = (Vibrator)this.getSystemService(VIBRATOR_SERVICE); layoutMain=(FrameLayout)findViewById(R.id.layoutMain); preview = (SurfaceView) findViewById(R.id.preview); previewHolder = preview.getHolder(); previewHolder.addCallback(surfaceCallback); previewHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS); mView=layoutMain; mDetector= (AreaDetectorView) findViewById(R.id.viewDetector); layoutDetectorArea=(FrameLayout) findViewById(R.id.layoutDetectArea); ToggleButton toggle = (ToggleButton) findViewById(R.id.simpleToggleButton); toggle.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { if (isChecked) { // The toggle is enabled } else { // The toggle is disabled } } }); if (Preferences.USE_RGB) { detector = new RgbMotionDetection(); } else if (Preferences.USE_LUMA) { detector = new LumaMotionDetection(); } else { // Using State based (aggregate map) detector = new AggregateLumaMotionDetection(); } } /** * {@inheritDoc} */ @Override public void onConfigurationChanged(Configuration newConfig) { super.onConfigurationChanged(newConfig); } /**dd: * Song play # 1 * Camera callback * * {@inheritDoc} */ @Override public void onPause() { super.onPause(); if(song!=null && song.isPlaying()) { song.stop();} camera.setPreviewCallback(null); if (inPreview) camera.stopPreview(); inPreview = false; camera.release(); camera = null; } /** * {@inheritDoc} */ @Override public void onResume() { super.onResume(); camera = Camera.open(); } private PreviewCallback previewCallback = new PreviewCallback() { /** * {@inheritDoc} */ @Override public void onPreviewFrame(byte[] data, Camera cam) { if (data == null) return; Camera.Size size = cam.getParameters().getPreviewSize(); if (size == null) return; if (!GlobalData.isPhoneInMotion()) { DetectionThread thread = new DetectionThread(data, size.width, size.height); thread.start(); } } }; private SurfaceHolder.Callback surfaceCallback = new SurfaceHolder.Callback() { /** * {@inheritDoc} */ @Override public void surfaceCreated(SurfaceHolder holder) { try { camera.setPreviewDisplay(previewHolder); camera.setPreviewCallback(previewCallback); } catch (Throwable t) { Log.e("Prek", "Exception in setPreviewDisplay()", t); } } /** * {@inheritDoc} */ @Override public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { if(camera != null) { Camera.Parameters parameters = camera.getParameters(); parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE); Camera.Size size = getBestPreviewSize(width, height, parameters); if (size != null) { parameters.setPreviewSize(size.width, size.height); Log.d(TAG, "Using width=" + size.width + " height=" + size.height); } camera.setParameters(parameters); camera.startPreview(); inPreview = true; } //AreaDetectorView.InitDetectionArea(); } /** * {@inheritDoc} */ @Override public void surfaceDestroyed(SurfaceHolder holder) { // Ignore } }; private static Camera.Size getBestPreviewSize(int width, int height, Camera.Parameters parameters) { Camera.Size result = null; for (Camera.Size size : parameters.getSupportedPreviewSizes()) { if (size.width <= width && size.height <= height) { if (result == null) { result = size; } else { int resultArea = result.width * result.height; int newArea = size.width * size.height; if (newArea > resultArea) result = size; } } } return result; } //***************Detection Class******************// private final class DetectionThread extends Thread { private byte[] data; private int width; private int height; public DetectionThread(byte[] data, int width, int height) { this.data = data; this.width = width; this.height = height; } /** * {@inheritDoc} */ @Override public void run() { if (!processing.compareAndSet(false, true)) return; // Log.d(TAG, "BEGIN PROCESSING..."); try { // Previous frame int[] pre = null; if (Preferences.SAVE_PREVIOUS) pre = detector.getPrevious(); // Current frame (with changes) // long bConversion = System.currentTimeMillis(); int[] img = null; if (Preferences.USE_RGB) { img = ImageProcessing.decodeYUV420SPtoRGB(data, width, height); } else { img = ImageProcessing.decodeYUV420SPtoLuma(data, width, height); } // Current frame (without changes) int[] org = null; if (Preferences.SAVE_ORIGINAL && img != null) org = img.clone(); if (img != null && detector.detect(img, width, height)) { // The delay is necessary to avoid taking a picture while in // the // middle of taking another. This problem can causes some // phones // to reboot. long now = System.currentTimeMillis(); if (now > (mReferenceTime + Preferences.PICTURE_DELAY)) { mReferenceTime = now; //mVibrator.vibrate(10); Bitmap previous = null; if (Preferences.SAVE_PREVIOUS && pre != null) { if (Preferences.USE_RGB) previous = ImageProcessing.rgbToBitmap(pre, width, height); else previous = ImageProcessing.lumaToGreyscale(pre, width, height); } Bitmap original = null; if (Preferences.SAVE_ORIGINAL && org != null) { if (Preferences.USE_RGB) original = ImageProcessing.rgbToBitmap(org, width, height); else original = ImageProcessing.lumaToGreyscale(org, width, height); } Bitmap bitmap = null; if (Preferences.SAVE_CHANGES) { if (Preferences.USE_RGB) bitmap = ImageProcessing.rgbToBitmap(img, width, height); else bitmap = ImageProcessing.lumaToGreyscale(img, width, height); } Log.i(TAG, "Saving.. previous=" + previous + " original=" + original + " bitmap=" + bitmap); Looper.prepare(); new SavePhotoTask().execute(previous, original, bitmap); } else { Log.i(TAG, "Not taking picture because not enough time has passed since the creation of the Surface"); } } } catch (Exception e) { e.printStackTrace(); } finally { processing.set(false); } // Log.d(TAG, "END PROCESSING..."); processing.set(false); } }; private static final class SavePhotoTask extends AsyncTask<Bitmap, Integer, Integer> { /** * {@inheritDoc} */ @Override protected Integer doInBackground(Bitmap... data) { for (int i = 0; i < data.length; i++) { Bitmap bitmap = data[i]; String name = String.valueOf(System.currentTimeMillis()); if (bitmap != null) save(name, bitmap); } return 1; } private void save(String name, Bitmap bitmap) { File photo = new File(Environment.getExternalStorageDirectory(), name + ".jpg"); if (photo.exists()) photo.delete(); try { FileOutputStream fos = new FileOutputStream(photo.getPath()); bitmap.compress(Bitmap.CompressFormat.JPEG, 100, fos); fos.close(); } catch (java.io.IOException e) { Log.e("PictureDemo", "Exception in photoCallback", e); } } } } AreaDetectorView.java Code: public class AreaDetectorView extends LinearLayout { public static int Width; public static int Height; private static Paint BoxPaint = null; private static Paint TextPaint = null; private static Paint ArrowPaint = null; private static Path mPath = null; private static Rect mRect = null; private static int lastX, lastY = 0; private static boolean mBoxTouched = false; private static boolean mArrowTouched = false; private static Context mContext; private static int ArrowWidth = 0; private static Paint BoxPaint2 = null; public AreaDetectorView(Context context) { super(context); mContext = context; } //attrs was not there public AreaDetectorView(Context context, AttributeSet attrs) { super(context,attrs); mContext = context; // TODO Auto-generated constructor stub if (!this.getRootView().isInEditMode()) { ArrowWidth =GetDisplayPixel(context, 30); } //InitDetectionArea(); InitMemberVariables(); setWillNotDraw(false); } public static int GetDisplayPixel(Context paramContext, int paramInt) { return (int)(paramInt * paramContext.getResources().getDisplayMetrics().density + 0.5F); } public static void InitMemberVariables() { if (BoxPaint == null) { BoxPaint = new Paint(); BoxPaint.setAntiAlias(true); BoxPaint.setStrokeWidth(2.0f); //BoxPaint.setStyle(Style.STROKE); BoxPaint.setStyle(Style.FILL_AND_STROKE); BoxPaint.setColor(ContextCompat.getColor(mContext, R.color.bwff_60)); } if (ArrowPaint == null) { ArrowPaint = new Paint(); ArrowPaint.setAntiAlias(true); ArrowPaint.setColor(ContextCompat.getColor(mContext,R.color.redDD)); ArrowPaint.setStyle(Style.FILL_AND_STROKE); } if (TextPaint == null) { TextPaint = new Paint(); TextPaint.setColor(ContextCompat.getColor(mContext,R.color.yellowL)); TextPaint.setTextSize(16); //txtPaint.setTypeface(lcd); TextPaint.setStyle(Style.FILL_AND_STROKE); } if (mPath == null) { mPath = new Path(); } else { mPath.reset(); } if (mRect == null) { mRect = new Rect(); } if (BoxPaint2 == null) { BoxPaint2 = new Paint(); BoxPaint2.setAntiAlias(true); BoxPaint2.setStrokeWidth(2.0f); //BoxPaint.setStyle(Style.STROKE); BoxPaint2.setStyle(Style.STROKE); BoxPaint2.setColor(ContextCompat.getColor(mContext,R.color.bwff_9e)); } } public static void InitDetectionArea() { try { int w = Prefe.DetectionArea.width(); int h = Prefe.DetectionArea.height(); int x = Prefe.DetectionArea.left; int y = Prefe.DetectionArea.top; // ver 2.6.0 if (Prefe.DetectionArea.left == 1 && Prefe.DetectionArea.top == 1 && Prefe.DetectionArea.right == 1 && Prefe.DetectionArea.bottom == 1) { w = Prefe.DisplayWidth / 4; h = Prefe.DisplayHeight / 3; // ver 2.5.9 w = Width / 4; h = Height / 3; Prefe.DetectorWidth = w; //UtilGeneralHelper.GetDisplayPixel(this, 100); Prefe.DetectorHeight = h; //UtilGeneralHelper.GetDisplayPixel(this, 100); x = (Prefe.DisplayWidth / 2) - (w / 2); y = (Prefe.DisplayHeight / 2) - (h / 2); // ver 2.5.9 x = (Width / 2) - (w / 2); y = (Height / 2) - (h / 2); } //Prefe.DetectionArea = new Rect(x, x, x + Prefe.DetectorWidth, x + Prefe.DetectorHeight); Prefe.DetectionArea = new Rect(x, y, x + w, y + h); Prefe.gDetectionBitmapInt = new int[Prefe.DetectionArea.width() * Prefe.DetectionArea.height()]; Prefe.gDetectionBitmapIntPrev = new int[Prefe.DetectionArea.width() * Prefe.DetectionArea.height()]; } catch (Exception e) { e.printStackTrace(); } } public static void SetDetectionArea(int x, int y, int w, int h) { try { Prefe.DetectionArea = new Rect(x, y, w, h); } catch (Exception e) { e.printStackTrace(); } } private void DrawAreaBox(Canvas canvas) { try { } catch (Exception e) { e.printStackTrace(); } } @Override protected void dispatchDraw(Canvas canvas) { try { if (this.getRootView().isInEditMode()) { super.dispatchDraw(canvas); return; } //canvas.save(Canvas.MATRIX_SAVE_FLAG); //Prefe.DetectionAreaOrient = UtilGeneralHelper.GetDetectRectByOrientation(); canvas.drawColor(0); mPath.reset(); canvas.drawRect(Prefe.DetectionArea, BoxPaint); mPath.moveTo(Prefe.DetectionArea.right - ArrowWidth, Prefe.DetectionArea.bottom); mPath.lineTo(Prefe.DetectionArea.right, Prefe.DetectionArea.bottom - ArrowWidth); mPath.lineTo(Prefe.DetectionArea.right, Prefe.DetectionArea.bottom); mPath.lineTo(Prefe.DetectionArea.right - ArrowWidth, Prefe.DetectionArea.bottom); mPath.close(); canvas.drawPath(mPath, ArrowPaint); mPath.reset(); //canvas.drawRect(Prefe.DetectionAreaOrient, BoxPaint2); //canvas.drawRect(Prefe.DetectionAreaOrientPort, BoxPaint2); TextPaint.setTextSize(16); //TextPaint.setLetterSpacing(2); TextPaint.setColor(ContextCompat.getColor(mContext,R.color.bwff)); TextPaint.getTextBounds(getResources().getString(R.string.str_detectarea), 0, 1, mRect); canvas.drawText(getResources().getString(R.string.str_detectarea), Prefe.DetectionArea.left + 4, Prefe.DetectionArea.top + 4 + mRect.height(), TextPaint); int recH = mRect.height(); TextPaint.setStrokeWidth(1.2f); TextPaint.setTextSize(18); TextPaint.setColor(ContextCompat.getColor(mContext,R.color.redD_9e)); TextPaint.getTextBounds(getResources().getString(R.string.str_dragandmove), 0, 1, mRect); canvas.drawText(getResources().getString(R.string.str_dragandmove), Prefe.DetectionArea.left + 4, Prefe.DetectionArea.top + 20 + mRect.height()*2, TextPaint); TextPaint.getTextBounds(getResources().getString(R.string.str_scalearea), 0, 1, mRect); canvas.drawText(getResources().getString(R.string.str_scalearea), Prefe.DetectionArea.left + 4, Prefe.DetectionArea.top + 36 + mRect.height()*3, TextPaint); super.dispatchDraw(canvas); //canvas.restore(); } catch (Exception e) { e.printStackTrace(); } } @Override protected void onDraw(Canvas canvas) { try { super.onDraw(canvas); invalidate(); } catch (Exception e) { e.printStackTrace(); } finally { } } @Override public boolean onTouchEvent(MotionEvent event) { boolean retValue = true; int X = (int)event.getX(); int Y = (int)event.getY(); //AppMain.txtLoc.setText(String.valueOf(X) + ", " + String.valueOf(Y)); switch (event.getAction()) { case MotionEvent.ACTION_DOWN: mBoxTouched = TouchedInBoxArea(X, Y); //AppMain.txtLoc.setText("BoxTouched: " + String.valueOf(mBoxTouched)); if (!mBoxTouched) break; lastX = X; lastY = Y; BoxPaint.setStyle(Style.FILL_AND_STROKE); BoxPaint.setColor(ContextCompat.getColor(mContext,R.color.redD_9e)); mArrowTouched = TouchedInArrow(X, Y); //AppMain.txtLoc.setText("ArrowTouched: " + String.valueOf(mBoxTouched)); if (mArrowTouched) { ArrowPaint.setColor(ContextCompat.getColor(mContext,R.color.bwff_9e)); } break; case MotionEvent.ACTION_MOVE: if (!mBoxTouched) break; int moveX = X - lastX; int moveY = Y - lastY; //AppMain.txtLoc.setText("Move X, Y: " + String.valueOf(moveX) + "," + String.valueOf(moveY)); if (!mArrowTouched) { if (Prefe.DetectionArea.left + moveX < 0) { break; } // if (Prefe.DetectionArea.right + moveX > Prefe.gDisplay.getWidth()) { // break; // } // ver 2.5.9 if (Prefe.DetectionArea.right + moveX > Width) { break; } if (Prefe.DetectionArea.top + moveY < 0) { break; } // if (Prefe.DetectionArea.bottom + moveY > Prefe.gDisplay.getHeight()) { // break; // } // ver 2.5.9 if (Prefe.DetectionArea.bottom + moveY > Height) { break; } } if (mArrowTouched) { if ((Prefe.DetectionArea.width() + moveX) < ArrowWidth * 2){ break; } if ((Prefe.DetectionArea.height() + moveY) < ArrowWidth * 2) { break; } Prefe.DetectionArea.right += moveX; Prefe.DetectionArea.bottom += moveY; //Log.i("DBG", "W,H: " + String.valueOf(Prefe.DetectionArea.width()) + "," + String.valueOf(Prefe.DetectionArea.height())); } else { Prefe.DetectionArea.left += moveX; Prefe.DetectionArea.right += moveX; Prefe.DetectionArea.top += moveY; Prefe.DetectionArea.bottom += moveY; } lastX = X; lastY = Y; //AppMain.txtLoc.setText(String.valueOf(Prefe.DetectionArea.left) + ", " + String.valueOf(Prefe.DetectionArea.top)); break; case MotionEvent.ACTION_UP: mBoxTouched = false; mArrowTouched = false; //BoxPaint.setStyle(Style.STROKE); BoxPaint.setStyle(Style.FILL_AND_STROKE); BoxPaint.setColor(ContextCompat.getColor(mContext,R.color.bwff_60)); ArrowPaint.setColor(ContextCompat.getColor(mContext,R.color.redDD)); //AppMain.txtLoc.setText(String.valueOf(Prefe.DetectionArea.left) + ", " + String.valueOf(Prefe.DetectionArea.top)); if (Prefe.DetectionArea.left < 0) { Prefe.DetectionArea.left = 0; } // if (Prefe.DetectionArea.right > Prefe.gDisplay.getWidth()) { // Prefe.DetectionArea.right = Prefe.gDisplay.getWidth(); // } // ver 2.5.9 if (Prefe.DetectionArea.right > Width) { Prefe.DetectionArea.right = Width; } if (Prefe.DetectionArea.top < 0) { Prefe.DetectionArea.top = 0; } // if (Prefe.DetectionArea.bottom > Prefe.gDisplay.getHeight()) { // Prefe.DetectionArea.bottom = Prefe.gDisplay.getHeight(); // } if (Prefe.DetectionArea.bottom > Height) { Prefe.DetectionArea.bottom = Height; } Prefe.gDetectionBitmapInt = new int[Prefe.DetectionArea.width() * Prefe.DetectionArea.height()]; Prefe.gDetectionBitmapIntPrev = new int[Prefe.DetectionArea.width() * Prefe.DetectionArea.height()]; //Prefe.gDetectionBitmapInt = null; //Prefe.gDetectionBitmapIntPrev = null; String area = String.valueOf(Prefe.DetectionArea.left) + "," + String.valueOf(Prefe.DetectionArea.top) + "," + String.valueOf(Prefe.DetectionArea.right) + "," + String.valueOf(Prefe.DetectionArea.bottom); // UtilGeneralHelper.SavePreferenceSetting(Prefe.gContext, Prefe.PREF_DETECTION_AREA_KEY, area); //Saving the value SharedPrefsUtils.setStringPreference(mContext.getApplicationContext(), Prefe.PREF_DETECTION_AREA_KEY, area); Log.v("TAG", SharedPrefsUtils.getStringPreference(mContext.getApplicationContext(),Prefe.PREF_DETECTION_AREA_KEY)); break; } invalidate(); return retValue; } private boolean TouchedInBoxArea(int x, int y) { boolean retValue = false; try { if (x > Prefe.DetectionArea.left && x < Prefe.DetectionArea.right) { if (y > Prefe.DetectionArea.top && y < Prefe.DetectionArea.bottom) { retValue = true; } } } catch (Exception e) { e.printStackTrace(); } return retValue; } private boolean TouchedInArrow(int x, int y) { boolean retValue = false; try { if (x > Prefe.DetectionArea.right - ArrowWidth && x < Prefe.DetectionArea.right) { if (y > Prefe.DetectionArea.bottom - ArrowWidth && y < Prefe.DetectionArea.bottom) { retValue = true; } } } catch (Exception e) { e.printStackTrace(); } return retValue; } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); int width = MeasureSpec.getSize(widthMeasureSpec); int height = MeasureSpec.getSize(heightMeasureSpec); setMeasuredDimension(width, height); Width = width; Height = height; InitDetectionArea(); } @Override protected void onFinishInflate() { super.onFinishInflate(); } @Override protected void onLayout(boolean changed, int l, int t, int r, int b) { // TODO Auto-generated method stub for (int i = 0; i < this.getChildCount()-1; i++){ (this.getChildAt(i)).layout(l, t, r, b); } if (changed) { // check width height if (r != Width || b != Height) { // size does not match } } } } Prefe.java Code: public class Prefe extends Application{ ... public static final String PREF_DETECTION_AREA_KEY = "pref_detection_area_key"; } static{ ... DetectionArea = new Rect(1, 1, 1, 1); } }