偷得浮生半桶水(半日闲), 好记性不如抄下来(烂笔头). 信息爆炸的时代, 学习是一项持续的工作.
全部博文(1750)
分类: LINUX
2010-01-29 12:05:46
This page will sumarize the efforts made to have Android running on the APF boards.
Note: Due to Android requirements (at least an ARM926 core), it is impossible to have it running on the APF9328 |
Contents[] |
sudo apt-get install uboot-mkimage mtd-utils
Theses environment variables install the Android and Armadeus folder in our home directory, but of course, it can be placed anywhere!
export ANDROID_SOURCE=~/android-eclair
export ANDROID_KERNEL=~/android-kernel
export ANDROID_SDK=~/android-sdk-linux
export ARMADEUS=~/armadeus-3.1
export PATH=${PATH}:${ANDROID_SDK}/tools:${ANDROID_SOURCE}/bin
List of different Android branch: The document describes how to set up our local work environment. Follow theses instructions until Installing Repo chapter.
mkdir $ANDROID_SOURCE
cd $ANDROID_SOURCE
mkdir bin
curl >$ANDROID_SOURCE/bin/repo
chmod a+x $ANDROID_SOURCE/bin/repo
repo init -u git://android.git.kernel.org/platform/manifest.git -b eclair
repo sync
Since android-sdk-1.5_r3 branch, the Linux kernel isn't with the Android source, We can download it in a compress archive (tar.gz) file with this (about (70Mib) or with git repository (more 300Mib)
mkdir $ANDROID_KERNEL
cd $ANDROID_KERNEL
git clone git://android.git.kernel.org/kernel/common.git android-2.6.29
Before compiling the kernel, we patch the source with the Armadeus patches. In second time, I will give the URL to retrieve Linux 2.6.29.4 patch.
Warning: Never export ARCH and CROSS_COMPILE environment variables because Android make use them too |
$ARMADEUS/buildroot/toolchain/patch-kernel.sh $ANDROID_KERNEL $ARMADEUS/downloads patch-2.6.29.4.bz2
$ARMADEUS/buildroot/toolchain/patch-kernel.sh $ANDROID_KERNEL $ARMADEUS/buildroot/target/device/armadeus/linux/kernel-patches/2.6.29.4 \*.patch{,.gz,.bz2}
mkdir $ANDROID_KERNEL/drivers/armadeus
cp -r $ARMADEUS/target/linux/modules/* $ANDROID_KERNEL/drivers/armadeus
For generate the Linux kernel, we retrieve the default apf27 Linux configuration and modify it for start Android.
cp $ARMADEUS/buildroot/target/device/armadeus/apf27/apf27-linux-2.6.29.config $ANDROID_KERNEL/arch/arm/configs/apf27_android_defconfig
cd $ANDROID_KERNEL
make ARCH=arm mrproper
make ARCH=arm apf27_android_defconfig
make ARCH=arm menuconfig
Make sure your kernel boots normally on your board. Then enable some Android specific configuration and make sure that your kernel still boots (with your standard file system).
Device Drivers --->
[*] Misc devices --->
[*] Android pmem allocator
Device Drivers --->
[*] Staging drivers --->
[ ] Exclude Staging drivers from being built (NEW)
...
Android --->
[*] Android Drivers
[*] Android Binder IPC Driver
<*> Android log driver
[ ] Android RAM buffer console
[*] Timed output class driver (NEW)
< > Android timed gpio driver (NEW)
[*] Android Low Memory Killer
General setup --->
[*] Enable the Anonymous Shared Memory Subsystem
Power management options --->
[*] Wake lock
[*] Wake lock stats (NEW)
[*] Userspace wake locks (NEW)
[*] Early suspend (NEW)
User-space screen access (Console switch on early-suspend) --->
(X) Sysfs interface
...
Device Drivers --->
Input device support --->
[*] Touchscreens --->
<*> TSC 2102 based touchscreens
...
<*> Hardware Monitoring support --->
Device Drivers --->
<*> Sound card support --->
--- Sound card support
<*> Advanced Linux Sound Architecture --->
[*] ARM sound devices --->
--- ARM sound
<*> i.MX27 SSI driver
<*> TSC210x alsa driver
Android don't use tslib library so we should add the calibration directly in ts drivers
edit $ANDROID_KERNEL/drivers/input/touchscreen/tsc2102_ts.c
Add new definitions for X and Y ranges
#define DRIVER_NAME "TSC210x Touchscreen"
#define X_AXIS_MAX 4000
#define X_AXIS_MIN 0
#define Y_AXIS_MAX 4200
#define Y_AXIS_MIN 100
#define PRESSURE_MIN 20
#define PRESSURE_MAX 40000
#define FACTOR 5000
Send touch event to Android when the user release the touchscreen
static void tsc210x_touch(int touching)
{
if (!touching) {
//input_report_abs(dev, ABS_X, 0);
//input_report_abs(dev, ABS_Y, 0);
input_report_key(dev, BTN_TOUCH, 0);
input_report_abs(dev, ABS_PRESSURE, 0);
input_sync(dev);
}
//input_report_key(dev, BTN_TOUCH, touching);
//do_poke_blanked_console = 1;
}
static void tsc210x_coords(int x, int y, int z1, int z2)
{
int p;
/* Calculate the touch resistance a la equation #1 */
if (z1 != 0)
p = x * (z2 - z1) / (z1 << 4) * FACTOR;
else
p = 1;
y = Y_AXIS_MAX - y;
input_report_key(dev, BTN_TOUCH, 1);
input_report_abs(dev, ABS_X, x);
input_report_abs(dev, ABS_Y, y);
input_report_abs(dev, ABS_PRESSURE, p);
input_sync(dev);
}
Calibrate the touchscreen with X and Y ranges
static int tsc210x_ts_probe(struct platform_device *pdev)
{
int status;
dev = input_allocate_device();
if (!dev)
return -ENOMEM;
status = tsc210x_touch_cb(tsc210x_touch);
if (status)
{
goto error;
}
status = tsc210x_coords_cb(tsc210x_coords);
if (status)
{
goto error;
}
dev->name = DRIVER_NAME;
dev->dev.parent = &pdev->dev;
dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
dev->keybit[BIT_WORD(BTN_TOUCH)] |= BIT_MASK(BTN_TOUCH);
dev->absbit[0] = BIT_MASK(ABS_X) | BIT_MASK(ABS_Y) | BIT_MASK(ABS_PRESSURE);
input_set_abs_params(dev, ABS_X, X_AXIS_MIN, X_AXIS_MAX, 0, 0);
input_set_abs_params(dev, ABS_Y, Y_AXIS_MIN, Y_AXIS_MAX, 0, 0);
input_set_abs_params(dev, ABS_PRESSURE, PRESSURE_MIN, PRESSURE_MAX, 0, 0);
status = input_register_device(dev);
if (status)
{
printk(KERN_INFO "Unable to register TSC210x as input device !\n");
goto error;
}
printk(DRIVER_NAME " driver initialized\n");
return 0;
error:
input_free_device(dev);
return status;
}
Compile the kernel and generate image kernel for U-Boot Loader
cd $ANDROID_KERNEL
make ARCH=arm CROSS_COMPILE=$ANDROID_SOURCE/prebuilt/linux-x86/toolchain/arm-eabi-4.2.1/bin/arm-eabi- uImage
cp $ANDROID_KERNEL/arch/arm/boot/uImage $TFTPBOOT/apf27-linux.bin
At the beginning, reboot happened over again even though Android logo appeared on board. Result of investigation, we found that battery power was returned with 0 when boot.. Then, we changed to notify full battery to Android by ignoring the information under /sys/class/power_supply so that to prevent the power down by low battery $ANDROID_SOURCE/frameworks/base/services/jni/com_android_server_BatteryService.cpp
static void setBooleanField(JNIEnv* env, jobject obj, const char* path, jfieldID fieldID)
{
const int SIZE = 16;
char buf[SIZE];
jboolean value = true; /* change false -> true */
/*!!!comment out!!!
if (readFromFile(path, buf, SIZE) > 0) {
if (buf[0] == '1') {
value = true;
}
}
*/
env->SetBooleanField(obj, fieldID, value);
}
static void setIntField(JNIEnv* env, jobject obj, const char* path, jfieldID fieldID)
{
const int SIZE = 128;
char buf[SIZE];
jint value = 100; /* change 0 -> 100 */
/*!!!comment out!!!
if (readFromFile(path, buf, SIZE) > 0) {
value = atoi(buf);
}
*/
env->SetIntField(obj, fieldID, value);
}
static void android_server_BatteryService_update(JNIEnv* env, jobject obj)
{
setBooleanField(env, obj, AC_ONLINE_PATH, gFieldIds.mAcOnline);
setBooleanField(env, obj, USB_ONLINE_PATH, gFieldIds.mUsbOnline);
setBooleanField(env, obj, BATTERY_PRESENT_PATH, gFieldIds.mBatteryPresent);
setIntField(env, obj, BATTERY_CAPACITY_PATH, gFieldIds.mBatteryLevel);
setIntField(env, obj, BATTERY_VOLTAGE_PATH, gFieldIds.mBatteryVoltage);
setIntField(env, obj, BATTERY_TEMPERATURE_PATH, gFieldIds.mBatteryTemperature);
/* Change */
env->SetIntField(obj, gFieldIds.mBatteryStatus, gConstants.statusFull);
env->SetIntField(obj, gFieldIds.mBatteryHealth, gConstants.healthGood);
env->SetObjectField(obj, gFieldIds.mBatteryTechnology, env->NewStringUTF("1"));
/*!!!comment out!!!
const int SIZE = 128;
char buf[SIZE];
if (readFromFile(BATTERY_STATUS_PATH, buf, SIZE) > 0)
env->SetIntField(obj, gFieldIds.mBatteryStatus, getBatteryStatus(buf));
if (readFromFile(BATTERY_HEALTH_PATH, buf, SIZE) > 0)
env->SetIntField(obj, gFieldIds.mBatteryHealth, getBatteryHealth(buf));
if (readFromFile(BATTERY_TECHNOLOGY_PATH, buf, SIZE) > 0)
env->SetObjectField(obj, gFieldIds.mBatteryTechnology, env->NewStringUTF(buf));
*/
}
For activate the audio, we should retrieve Alsa android module whose not directly add in the source
cd $ANDROID_SOURCE/external
git clone git://android.git.kernel.org/platform/external/alsa-lib.git
git clone git://android.git.kernel.org/platform/external/alsa-utils.git
cd $ANDROID_SOURCE/hardware
git clone git://android.git.kernel.org/platform/hardware/alsa_sound.git
edit $ANDROID_SOURCE/build/target/board/generic/BoardConfig.mk and modify the audio divers used by Android
# HAVE_HTC_AUDIO_DRIVER := true
# BOARD_USES_GENERIC_AUDIO := true
BOARD_USES_ALSA_AUDIO := true
BUILD_WITH_ALSA_UTILS := true
edit $ANDROID_SOURCE/hardware/alsa_sound/AudioHardwareALSA.cpp and change bufferSize to 8192 in twice StreamDefaults structures
edit $ANDROID_SOURCE/system/core/init/device.c and add audio device in Linux devices
static struct perms_ devperms[] = {
{ "/dev/null", 0666, AID_ROOT, AID_ROOT, 0 },
...
{ "/dev/qmi1", 0640, AID_RADIO, AID_RADIO, 0 },
{ "/dev/qmi2", 0640, AID_RADIO, AID_RADIO, 0 },
// Add this line
{ "/dev/snd/", 0664, AID_SYSTEM, AID_AUDIO, 1 },
{ NULL, 0, 0, 0, 0 },
};
static void handle_device_event(struct uevent *uevent)
{
char devpath[96];
char *base, *name;
int block;
...
} else if(!strncmp(uevent->subsystem, "mtd", 3)) {
base = "/dev/mtd/";
mkdir(base, 0755);
// add this conditionnal block
} else if(!strncmp(uevent->subsystem, "sound", 5)) {
base = "/dev/snd/";
mkdir(base, 0755);
} else if(!strncmp(uevent->subsystem, "misc", 4) &&
!strncmp(name, "log_", 4)) {
base = "/dev/log/";
mkdir(base, 0755);
name += 4;
} else
base = "/dev/";
}
Add audio files in Android files system
mkdir $ANDROID_SOURCE/system/core/rootdir/media
mkdir $ANDROID_SOURCE/system/core/rootdir/media/audio
mkdir $ANDROID_SOURCE/system/core/rootdir/media/audio/ui
mkdir $ANDROID_SOURCE/system/core/rootdir/media/audio/alarms
mkdir $ANDROID_SOURCE/system/core/rootdir/media/audio/notifications
mkdir $ANDROID_SOURCE/system/core/rootdir/media/audio/ringtones
cp $ANDROID_SOURCE/frameworks/base/data/sounds/effects/* $ANDROID_SOURCE/system/core/rootdir/media/audio/ui/
cp $ANDROID_SOURCE/frameworks/base/data/sounds/Alarm_* $ANDROID_SOURCE/system/core/rootdir/media/audio/alarms/
cp $ANDROID_SOURCE/frameworks/base/data/sounds/notifications/* $ANDROID_SOURCE/system/core/rootdir/media/audio/notifications/
cp $ANDROID_SOURCE/frameworks/base/data/sounds/Ring_* $ANDROID_SOURCE/system/core/rootdir/media/audio/ringtones/
Edit $ANDROID_SOURCE/system/core/rootdir/init.rc, comment the mount roofs in read only mode and mount yaffs2 lines like this:
# setup the global environment
export PATH /sbin:/system/sbin:/system/bin:/system/xbin
export LD_LIBRARY_PATH /system/lib
export ANDROID_BOOTLOGO 1
export ANDROID_ROOT /system
export ANDROID_ASSETS /system/app
export ANDROID_DATA /data
export EXTERNAL_STORAGE /sdcard
export BOOTCLASSPATH /system/framework/core.jar:/system/framework/ext.jar:/system/framework/framework.jar:/system/framework/android.policy.jar:/system/framework/services.jar
mount rootfs rootfs / rw remount
# Backward compatibility
symlink /system/etc /etc
# create mountpoints and mount tmpfs on sqlite_stmt_journals
mkdir /sdcard 0000 system system
mkdir /system
mkdir /data 0771 system system
mkdir /cache 0770 system cache
mkdir /sqlite_stmt_journals 01777 root root
mount tmpfs tmpfs /sqlite_stmt_journals size=4m
mount rootfs rootfs / ro remount
write /proc/sys/kernel/panic_on_oops 1
write /proc/sys/kernel/hung_task_timeout_secs 0
write /proc/cpu/alignment 4
write /proc/sys/kernel/sched_latency_ns 10000000
write /proc/sys/kernel/sched_wakeup_granularity_ns 2000000
# mount mtd partitions
# Mount the SD Card partition
setprop EXTERNAL_STORAGE_STATE mounted
mount vfat /dev/block/mmcblk0p1 /sdcard nosuid nodev
# We chown/chmod /data again so because mount is run as root + defaults
mount ext2 /dev/block/mmcblk0p2 /data nosuid nodev
chown system system /data
chmod 0771 /data
# Same reason as /data above
chown system cache /cache
chmod 0770 /cache
# This may have been created by the recovery system with odd permissions
chown system system /cache/recovery
chmod 0770 /cache/recovery
$ cd $ANDROID_SOURCE
$ make
Android emulator has 3 basic images on $ANDROID_SOURCE/tools/lib/images directory.
Android’s root file system is generated in $ANDROID_SOURCE/out/target/product/generic. We will create a folder containing all Android files images.
sudo rm -rf $ANDROID_SOURCE/rootfs/
cd $ANDROID_SOURCE/out/target/product/generic
mkdir $ANDROID_SOURCE/rootfs
cp -a root/* $ANDROID_SOURCE/rootfs/
cp -a system/* $ANDROID_SOURCE/rootfs/system/
cd $ANDROID_SOURCE/rootfs
sudo chown -R root.root .
sudo chmod -R a+rwX data system
Actually, Android should use a file system how support mmap function like yaffs2, ext2 or ubifs. Unfortunaly, U-Boot support only jffs2 or ext2. So we will use ext2 on a µSD for data.
We will create two partitions on our mmc/µSD card, The first one will use for Android memory card, the second one will use for Android file system. First connect your card reader to your workstation, with the mmc/µSD card inside. Type the dmesg command to see which device is used by your workstation. Let’s assume that this device is /dev/sdb
$ dmesg
...
[ 9145.613954] sdb: sdb1 sdb2
[ 9145.615125] sd 10:0:0:0: [sdc] Attached SCSI removable disk
[ 9145.615258] sd 10:0:0:0: Attached scsi generic sg3 type 0
Type the mount command to check your currently mounted partitions. If MMC/SD partitions are mounted, unmount them.
In a terminal edit partitions with fdisk:
sudo fdisk /dev/sdb
Delete any existing partition with the d command.
Now, create the boot partition:
Command (m for help): n
Command action
e extended
p primary partition (1-4)
p
Partition number (1-4): 1
First cylinder (1-495, default 1): 1
Last cylinder, +cylinders or +size{K,M,G} (1-239, default 239): +1G
Change its type to FAT32:
Command (m for help): t
Selected partition 1
Hex code (type L to list codes): c
Changed system type of partition 1 to c (W95 FAT32 (LBA))
Using the n command again, create a second partition filling up the rest of your card (just accept default values).
Now, format the partitions in your card:
sudo mkfs.vfat -n MemoryCard -F 32 /dev/sdb1
sudo mkfs.ext2 -L data /dev/sdb2
$ sudo mkfs.jffs2 -n -e 0x20000 --pad=0x700000 -r $ANDROID_SOURCE/rootfs -o $TFTPBOOT/apf27-rootfs.arm.jffs2
The last thing left to do is to specify how the board boots Linux.
In the U-boot prompt, make the mmc boot is on second partition of the mmc/µSD card
setenv addjffsargs 'setenv bootargs ${bootargs} root=/dev/mtdblock4 rootfstype=jffs2 init=/init'
setenv bootcmd run mmcboot
saveenv
run update_kernel
run update_rootfs
Installing the Android Development Tools (ADT) Trace with logcat with Eclipse-ADT
export ADBHOST=w.x.y.z
adb kill-server
adb start-server
Documentation on Android emulator
cd $ANDROID_SOURCE/kernel
make ARCH=arm goldfish_defconfig
make ARCH=arm CROSS_COMPILE=$ANDROID_SOURCE/prebuilt/linux-x86/toolchain/arm-eabi-4.2.1/bin/arm-eabi
Create AVD (Android Virtual Device)
$ANDROID_SDK/tools/android create avd -n APF27-H -t 4 -s 272x480
$ANDROID_SDK/tools/android create avd -n APF27-L -t 4 -s 480x272
$ANDROID_SOURCE/out/host/linux-x86/bin/emulator -avd APF27-H -sysdir $ANDROID_SOURCE/out/target/product/generic/ -kernel $ANDROID_SOURCE/kernel/arch/arm/boot/zImage -data $ANDROID_SOURCE/out/target/product/generic/userdata.img -ramdisk $ANDROID_SOURCE/out/target/product/generic/ramdisk.img -system $ANDROID_SOURCE/out/target/product/generic/system.img
Thanks to Xavier Romanens and Fabrice Carrel form Ecole d'ingénieurs et d'architectes de Fribourg for their contributions.