adb in Android

Overview of adb in Android:

adb

Three Elements of adb:

  • adb clients
    • executable with subcommand
    • ”adb shell”, ”adb logcat” : the end point of host side
  • adb server
    • running on host on back-ground
    • act as proxy between adb clients and adbd
  • adb daemon (adbd)
    • running on target device
    • started by init, if die, restarted by init again

Sequence chart:

adb2

When does adb server start?

  • Explicitly, “adb start-server”
    • It starts adb server as back ground process
  • Usually it does automatically on demand. You don’t have to do “adb start-server”
  • When you want to restart adb server, do “adb kill-server” && “sudo adb start-server
  • Actually, adb clients and adb server shares same executable
    • adb start-server” equals “adb fork-server server &”

 

ADB Source code:

  • system/core/adb in Android source tree
    • From this directory adb and adbd are built
  • common files between adb and adbd
    • adb.c, fdevent.c, transort.c, transport_local.c, tansport_usb.c, service.c, sockets.c, util.c
  • files only for adbd
    • backup_service.c, file_sync_service.c, jdwp_service.c, framebuffer_service.c, remount_services.c, usb_linux_clients.c, log_service.c
  • files only for adb
    • console.c, adb_clients.c, file_sync_client.c, usb_vendors.c, get_my_path_{linux,darwin,windows,freebsd}.c, usb_{linux,macos,libusb,windows}.c

 

USB Vendor ID:

  • When connecting USB device, adb checks USB Vendor ID
  • Many USB Vendor IDs are hard coded in adb. (But not enough)
  • To add USB Vendor ID, make ”$HOME/.android/adb_usb.ini” and write one ID in one line or add rules to the file /etc/udev/rules.d/99-adb.rules

For e.g.:

$ adb devices
List of devices attached 
4df15d6e02a55f15    device
????????????    no permissions

First check with lsusb:

$ lsusb
...
Bus 002 Device 050: ID 04e8:6860 Samsung Electronics Co., Ltd GT-I9100 Phone ...
Bus 002 Device 049: ID 18d1:4e42 Google Inc. 

Checking the permissions on those:

$ ls -l /dev/bus/usb/002/{049,050}
crw-rw-r--  1 root root    189, 176 Oct 10 10:09 /dev/bus/usb/002/049
crw-rw-r--+ 1 root plugdev 189, 177 Oct 10 10:12 /dev/bus/usb/002/050

Where did that “plugdev” group come from?

$ cd /lib/udev/rules.d/
$ grep -R "6860.*plugdev" .
./40-libgphoto2-2.rules:ATTRS{idVendor}=="0bb4", ATTRS{idProduct}=="6860", \
  ENV{ID_GPHOTO2}="1", ENV{GPHOTO2_DRIVER}="proprietary", \
  ENV{ID_MEDIA_PLAYER}="1", MODE="0664", GROUP="plugdev"
./40-libgphoto2-2.rules:ATTRS{idVendor}=="04e8", ATTRS{idProduct}=="6860", \
  ENV{ID_GPHOTO2}="1", ENV{GPHOTO2_DRIVER}="proprietary", \
  ENV{ID_MEDIA_PLAYER}="1", MODE="0664", GROUP="plugdev"

(I’ve wrapped those lines)

Note the GROUP="plugdev" lines. Also note that this doesn’t work for the other device ID:

$ grep -Ri "4e42.*plugdev" .

(nothing is returned)

Create a file /etc/udev/rules.d/99-adb.rules containing the following line:

ATTRS{idVendor}=="18d1", ATTRS{idProduct}=="4e42", ENV{ID_GPHOTO2}="1",
  ENV{GPHOTO2_DRIVER}="proprietary", ENV{ID_MEDIA_PLAYER}="1",
  MODE="0664", GROUP="plugdev"

This should be a single line, I’ve wrapped it here for readability

Restart udev

$ sudo udevadm control --reload-rules
$ sudo service udev restart

That’s it

Unplug/replug your device.

Try it

$ adb devices
List of devices attached 
4df15d6e02a55f15    device
015d2109ce67fa0c    device

 

Switching transport mode: (USB->TCP)

Switching USB mode to TCP mode 

$ adb shell netcfg 

lo UP 127.0.0.1 255.0.0.0 0x00000049 

eth0 UP 192.168.1.139 255.255.255.0 0x00001043 

$ adb tcpip 5555 

restarting in TCP mode port : 5555 

$ adb devices 

List of devices attached 

$

disconnected from USB. Then restart adb server with specifying target IP address.

$ adb kill-server 

$ ADBHOST=192.168.1.139 adb devices 

* daemon not running. starting it now on port 5037 * 

* daemon started successfully * 

List of devices attached 

emulator-5554 device 

$

 

Other Case:

=========================================
# adb devices
List of devices attached
4d00f9169907301b        unauthorized
=========================================
  • Get the public key from the client phone (adb host)

    cat /data/.android/adbkey.pub

  • copy the above public key to the target phone’s /data/misc/adb/adb_keys location. (you may need to stop the adb daemon first with stop adbd)

    cat /data/misc/adb/adb_keys

verify both cat outputs match.

try restarting adb daemon on target start adbd or just reboot them.

If you are having problems reading or writing to ADB KEYS in above steps, try setting environment variable ADB_KEYS_PATH with a temporary path (eg: /data/local/tmp). Refer to that link it goes intomore details

    "On the host, the user public/private key pair is automatically generated,
    if it does not exist, when the adb daemon starts and is stored in
    $HOME/.android/adb_key(.pub) or in $ANDROID_SDK_HOME on windows. If needed,
    the ADB_KEYS_PATH env variable may be set to a :-separated (; under
    Windows) list of private keys, e.g. company-wide or vendor keys.

    On the device, vendors public keys are installed at build time in
    /adb_keys. User-installed keys are stored in /data/misc/adb/adb_keys"

 

adb from root to user mode:

If you used – “adb root”, you would have got the following message:

$ adb root
* daemon not running. starting it now on port 5037 *
* daemon started successfully *
restarting adbd as root

to get out of the root mode, you can use:

$ adb unroot
restarting adbd as non root

adb kill-server and adb start-server only control the adb daemon on the PC side. You need to restart adbd daemon on the device itself after reverting the service.adb.root property change done by adb root:

~$ adb shell id
uid=2000(shell) gid=2000(shell)

~$ adb root
restarting adbd as root

~$ adb shell id
uid=0(root) gid=0(root)

~$ adb shell 'setprop service.adb.root 0; setprop ctl.restart adbd'

~$ adb shell id
uid=2000(shell) gid=2000(shell)

OR

stop adbd && setprop service.adb.root 0 && start adbd &

This command will stop adbd, then setprop service.adb.root 0 if adbd has been successfully stopped, and finally restart adbd should the .root property have successfully been set to 0. And all this will be done in the background thanks to the last &.

 

 

 Ref.:

https://events.linuxfoundation.org/images/stories/pdf/lf_abs12_kobayashi.pdf

http://stackoverflow.com/questions/14460656/android-debug-bridge-adb-device-no-permissions/19291975#19291975

http://stackoverflow.com/questions/26213954/how-to-solve-adb-device-unauthorized-in-android-adb-host-device

http://stackoverflow.com/questions/15336215/how-to-restart-adb-from-root-to-user-mode

Advertisements

Android Boot Process

Mainly there are 6 partitions in Android phones, tablets and any other Android devices. Below is the list of partition for Android File System.

  • /boot
  • /system
  • /recovery
  • /data
  • /cache
  • /misc

Note from author: There might be some other partitions available & may also differs from Model to Model. But baseline partitions mention above do not change in any Android devices.

 

Note to User(s):Boot.img, System.img, & recovery.img are all flashable partitions with a unlocked boot loader.

For SD Card Fie System Partitions.

  • /sdcard
  • /sd-ext

Note to User(s):Only /sdcard partition can be found in all Android devices and SD-Ext is present only in select devices.

Now that we know the partitions avalable of our device, we can see what can be changed or wiped or erased. To illustrate: Wiping stock recovery and install TWRP recovery means just changing the recovery partition is all.

Now Let us start with the brief intro for each partition. I would be dwelling much on each of these but just brief intro to each for wider audience.

/boot

Boot partition of your Android device, as the name suggests. It includes the android kernel and the ramdisk.  The device will not boot without this partition. Wiping this partition from recovery should only be done if absolutely required and once done, the device must NOT be rebooted before installing a new one, which can be done by installing a ROM that includes a /boot partition.

/system

As the name suggests, this partition contains the entire Android OS, other than the kernel and the ramdisk. This includes the Android GUI and all the system applications that come pre-installed on the device. Wiping this partition will remove Android from the device without rendering it unbootable, and you will still be able to put the phone into recovery or bootloader mode to install a new ROM.

/recovery

This is specially designed for backup. The recovery partition can be considered as an alternative boot partition, that lets the device boot into a recovery console for performing advanced recovery and maintenance operations on it.

/data

As the name suggest, it is userdata partition. This partition contains the user’s data like your contacts, sms, settings and all android applications that you have installed. While you are doing factory reset on your device, this partition will wipe out, Then your device will be in the state, when you use for he first time, or the way it was after the last official or custom ROM installation.

/cache

I hope you have some idea about cache, as you are expert on internet browsing. This is the partition where Android stores frequently accessed data and app components. Wiping the cache doesn’t effect your personal data but simply gets rid of the existing data there, which gets automatically rebuilt as you continue using the device.

/misc

This partition contains miscellaneous system settings in form of on/off switches. These settings may include CID (Carrier or Region ID), USB configuration and certain hardware settings etc. This is an important partition and if it is corrupt or missing, several of the device’s features will will not function normally.

Android device execute following steps when you press power switch

Android Boot Sequence / Process

Step 1 : Power On and System Startup

When power start Boot ROM code start execution from pre defined location which is hardwired on ROM. It load Bootloader into RAM and start execution

Step 2 : Bootloader

Bootloader is small program which runs before Android operating system running. Bootloader is first program to run so It is specific for board and processor. Device manufacturer either use popular bootloaders like redboot,uboot, qi bootloader or they develop own bootloaders, It’s not part of Android Operating System. bootloader is the place where OEMs and Carriers put there locks and restrictions.

Bootloader perform execution in two stages, first stage It to detect external RAM and load program which helps in second stage, In second stage bootloader setup network, memory, etc. which requires to run kernel, bootloader is able to provide configuration parameters or inputs to the kernel for specific purpose.

Android bootloader can be found at

<Android Source>\bootable\bootloader\legacy\usbloaderlegacy loader contain two important files that need to address here.

  • init.s – Initializes stacks, zeros the BSS segments, call _main() in main.c
  • main.c – Initializes hardware (clocks, board, keypad, console), creates Linux tags

If you are interested in more info, you can refer to Android 101: What Is A Bootloader?

Step 3: Kernel

Android kernel start similar way as desktop linux kernel starts, as kernel launch it start setup cache, protected memory, scheduling, loads drivers. When kernel finish system setup first thing it look for “init” in system files and launch root process or first process of system.

Step 4: init process

init it very first process, we can say it is root process or BOSS of all processes. init process has two responsibilities

  • mount directories like /sys, /dev, /proc
  • run init.rc script.

init process can be found at init : <android source>/system/core/init
init.rc file can be found in source tree at <android source>/system/core/rootdir/init.rc
readme.txt file can be found in source tree at <andorid source>/system/core/init/readme.txt

Android has specific format and rules for init.rc files. In Android we call it as “Android Init Language

The Android Init Language consists of four broad classes of statements,which are Actions, Commands, Services, and Options.
Action : Actions are named sequences of commands.  Actions have a trigger which is used to determine when the action should occur.
Syntax
on <trigger>
<command>
<command>
<command>

Service :  Services are programs which init launches and (optionally) restarts when they exit.  Syntax
service <name> <pathname> [ <argument> ]*
<option>
<option>

Options : Options are modifiers to services.  They affect how and when init runs the service.

Looking @ default init.rc file; listed are some major events and services.

Action  / Service
Description
on  early-init
Set  init and its forked children’s oom_adj.
Set  the security context for the init process.
on  init
setup  the global environment
Create  cgroup mount point for cpu accounting
and  many
on  fs
mount  mtd partitions
on  post-fs
change  permissions of system directories
on  post-fs-data
change  permission of /data folders and sub folders
on  boot
basic  network init ,Memory Management ,etc
service  servicemanager
start  system manager to manage all native services like location, audio, shared  preference etc..
service  zygote
start  zygote as app_process

At this stage you can see “Android/OEM” logo on device screen.

Step 5: Zygote and Dalvik

In a Java, We know that separate Virtual Machine(VMs) instance will popup in memory for separate per app, In case of Android app should launch as quick as possible, If Android os launch different instance of Dalvik VM for every app then it consume lots of memory and time. so, to overcome this problem Android OS as system named “Zygote”. Zygote enable shared code across Dalvik VM, lower memory footprint and minimal startup time. Zygote is a VM process that starts at system boot time as we know in previous step. Zygote preloads and initialize core library classes.  Normally there core classes are read-only and part of Android SDK or Core frameworks. In Java VM each instance has it’s own copy of core library class files and heap objects.

Zygote loading process

Source Code :<Android Source> /frameworks/base/core/java/com/android/internal/os/ZygoteInit.java

  • registerZygoteSocket() –  Registers a server socket for zygote command connections
  • preloadClasses() – “preloaded-classes” is simple text file contains list of classes that need to be preloaded, you cna find “preloaded-classes” file at <Android Source>/frameworks/base
  • preloadResources() – preloadReaources means native themes and layouts, everything that include android.R file will be load using this method.

At this time you can see bootanimation

Step 6: System  Service or Services

After complete above steps, runtime request Zygote to launch system servers. System Servers are written in native and java both, System servers we can consider as process, The same system server is available as System Services in Android SDK. System server contain all system services.

Zygote fork new process to launch system services. You can find source code in ZygoteInit class and “startSystemServer” method.

Core Services which gets started along with the boot process

  • Starting Power Manager
  • Creating Activity Manager
  • Starting Telephony Registry
  • Starting Package Manager
  • Set Activity Manager Service as System Process
  • Starting Context Manager
  • Starting System Context Providers
  • Starting Battery Service
  • Starting Alarm Manager
  • Starting Sensor Service
  • Starting Window Manager
  • Starting Bluetooth Service
  • Starting Mount Service

Other services after booting process are

  • Starting Status Bar Service
  • Starting Hardware Service
  • Starting NetStat Service
  • Starting Connectivity Service
  • Starting Notification Manager
  • Starting DeviceStorageMonitor Service
  • Starting Location Manager
  • Starting Search Service
  • Starting Clipboard Service
  • Starting Checkin Service
  • Starting Wallpaper Service
  • Starting Audio Service
  • Starting HeadsetObserver
  • Starting AdbSettingsObserver

Step 7 : Boot Completed

Once System Services up and running in memory, Android has completed booting process, At this time “ACTION_BOOT_COMPLETED” standard broadcast action will fire.
You Smart Phone is now at your disposal.

 

Ref.:

https://community.nxp.com/docs/DOC-102546

http://en.miui.com/thread-15659-1-1.html

How to extract kernel configuration from android kernel or boot.img and build related kernel for the device

To build a new kernel for specified device, you need to make a configuration:

For example, all of configuration fiiles: KCONFIG will be placed at related folders.

When you type the command:

make def_config

or

make menuconfig

to configure the kernel.

Afterall, all the configuration will be written to the one file “.config” at <kernel_source_dir>

 

So if you wanna build a specified kernel for specified device, the simpliest way to get the kernel configuration is to extract it from the original kernel.

Usually, you will not be able to download the kernel image itself.

but it’s easy to get the boot.img which is consisted with kernel and ramdisk images.

 

After you get the boot.img

Decompress it:

$ unmkbootimg -i boot.img
kernel written to ‘kernel‘ (6682776 bytes)
ramdisk written to ‘ramdisk.cpio.gz’ (913311 bytes)

To rebuild this boot image, you can use the command:
mkbootimg –base 0 –pagesize 2048 –kernel_offset 0x80208000 –ramdisk_offset 0x82200000 –second_offset 0x81100000 –tags_offset 0x80200100 –cmdline ‘console=ttyHSL0,115200,n8 androidboot.hardware=flo user_debug=31 msm_rtb.filter=0x3F ehci-hcd.park=3 vmalloc=340M’ –kernel kernel –ramdisk ramdisk.cpio.gz -o boot.img

You will have kernel and ramdisk in your current folder.

 

Then you need a script named extract-ikconfig

you can download it from following link:

https://github.com/torvalds/linux/blob/master/scripts/extract-ikconfig

$ chmod +x extract-ikconfig

$ extract-ikconfig kernel > kernel_config

 

then you can put the kernel_config to the <kernel_source_dir> renaming it with “.config” and compile the kernel for the device.

 

For detailed steps of compiling the kernel, remaking the boot.img and flash to the device, you can follow my previous articles.

 

^___________________^

 

 

 

 

 

How to unpack boot.img modify the file and repack the image then flash

Refer my previous article “HOW TO BUILD ANDROID KERNEL AND FLASH IT TO THE TARGET” to get the boot.img for device.

you can extract the image from the device or you can download it from manufacturer’s website.

 

Precondition:

To decompress, modify and Re-compress the boot image you need following tools.

  1. mkbootimg & unmkbootimg
  2. mkbootfs

Download thoes tools into a folder:

$ mkdir down_tools

$ mkdir tool-chain

$ cd down_tools

$ git clone https://github.com/osm0sis/mkbootimg.git

$ git clone https://github.com/osm0sis/mkbootfs.git

$ cd mkbootimg

$ make

$ cp mkbootimg unmkbootimg ../tool-chain

$ cd ..

$ cd mkbootfs

$ make

$ cp mkbootfs ../tool-chain

$ export  PATH=tool-chain-path/bin:$PATH

 

Extract ramdisk from boot.img:

$ unmkbootimg -i boot.img
kernel written to ‘kernel’ (6682776 bytes)
ramdisk written to ‘ramdisk.cpio.gz’ (913311 bytes)

To rebuild this boot image, you can use the command:
mkbootimg –base 0 –pagesize 2048 –kernel_offset 0x80208000 –ramdisk_offset 0x82200000 –second_offset 0x81100000 –tags_offset 0x80200100 –cmdline ‘console=ttyHSL0,115200,n8 androidboot.hardware=flo user_debug=31 msm_rtb.filter=0x3F ehci-hcd.park=3 vmalloc=340M’ –kernel kernel –ramdisk ramdisk.cpio.gz -o boot.img

Now you will get two files – kernel and ramdisk.cpio.gz

Mark command to re-build the boot.img later.

 

Decompress ramdisk to the real files:

The ramdisk format is a bit odd. The files have first been concatenated into an archive using cpio (this means the files are all strung together into one single big file, but not compressed), then compressed using gzip. So, to undo all this, we need to first gunzip the ramdisk and then use cpio to extract the files from the archive. This is mentioned, for example, here.

So, make a new directory called ramdisk. cd into it. Then use a combination of gunzip and cpio to extract the initramfs.cpio.gz file. Here’s the commands:

$ mkdir ramdisk
$ cd ramdisk
$ gunzip -c ../ramdisk.cpio.gz | cpio -i
$ ls
charger file_contexts init.flo.diag.rc init.trace.rc oem sbin service_contexts ueventd.rc
data fstab.flo init.flo.rc init.usb.configfs.rc proc seapp_contexts sys
default.prop init init.flo.usb.rc init.usb.rc property_contexts selinux_version system
dev init.environ.rc init.rc init.zygote32.rc res sepolicy ueventd.flo.rc

The -c switch on gunzip makes it send its output to the standard output (i.e. the terminal). This is then piped (the | symbol) to cpio. The -i switch with cpio makes it work in copy-in mode – it copies files in from an archive, and outputs them as real files. Now have a look at the contents of the ramdisk directory.

 

You may have some changes to make for this directory.

Now it’s time to modify the ramdisk!

Blah Blah~

 

Compress the files back into a ramdisk:

I tried method from online tutorial which saying that using cpio and gzip will work for creating the ramdisk like following:

However, when carried through to completion, this does not result in a bootable image. I don’t know what mkbootfs does, but it seems irrelevant – why not just reverse the action of gunzip and cpio to get back to a ramdisk file? In fact, this is exactly what’s described here. While still in the ramdisk directory, run the following:

find . | cpio -o -H newc | gzip > ../newramdisk.cpio.gz

This consists of three parts. find . spits out (to the terminal) a list of all filenames in the current (ramdisk) directory, including files in sub-directories. This is piped to cpio. It uses the switches -o for copy-out mode, so it combines files from find . into an archive, and -H newc to specify the output format. This is then piped to gzipwhich compresses the output from cpio into a final, new ramdisk file, called newramdisk.cpio.gz. Here’s the resulting files in the recovery directory now

However that failed me with system unbootable.

so I tried with other method – using mkbootfs:

$ mkbootfs ramdisk | gzip > ramdisk-new.gz

Then finally it worked for me. don’t know reason. and didn’t have time to figure it out.

(If you’re interested, compare the file sizes of the ramdisk files produced by mkbootfs and the other command – they are different, which probably explains why the final image doesn’t boot. On mine, mkbootfs produced a file 2035130 bytes in size, while the find . | cpio -o -H newc | gzip > ../newramdisk.cpio.gz command produced 2033625 bytes.)

the tutorial says mkbootfs didn’t work out for him, but oppositely the cpio and gz didn’t work out for me.

Now let’s recompress the boot.img

$ cd ..

$ mkbootimg –base 0 –pagesize 2048 –kernel_offset 0x80208000 –ramdisk_offset 0x82200000 –second_offset 0x81100000 –tags_offset 0x80200100 –cmdline ‘console=ttyHSL0,115200,n8 androidboot.hardware=flo user_debug=31 msm_rtb.filter=0x3F ehci-hcd.park=3 vmalloc=340M’ –kernel zImage –ramdisk ramdisk-new.gz -o newboot.img

 

Flash the device:

$ adb reboot-bootloader

$ sudo fastboot flash boot newboot.img

$ sudo fastboot reboot

 

walah, you will able to see the ramdisk is changed now!

 

 

 

Ref.:

https://github.com/pbatard/bootimg-tools

https://github.com/osm0sis/mkbootimg

https://github.com/osm0sis/mkbootfs

http://whiteboard.ping.se/Android/Rooting

http://www.imajeenyus.com/computer/20130301_android_tablet/android/unpack_repack_recovery_image.html

 

How to build Android kernel and flash it to the target

0) Pre-requirement

0-1) Download the build-essential.

$ sudo apt-get update

$sudo apt-get install build-essential

0-2) Activate developer mode && Enable USB debugging

– Activate developer mode : Setting – Build number – Tap ‘Build number’ seven times

– Enable USB Debugging : (After activate developer mode) Setting – Developer option – Check ‘USB debugging’

1) Build Kernel

 1-1) tool-chain download

$ mkdir tool-chain-path

$ cd tool-chain-path

$ git clone https://android.googlesource.com/platform/prebuilts/gcc/linux-x86/arm/arm-eabi-4.6

$ export  PATH=tool-chain-path/bin:$PATH

1-2) kernel download

$ git clone https://android.googlesource.com/kernel/msm.git

$ cd msm

$ git branch -r

$ git checkout origin/android-msm-flo-3.4-marshmallow-mr2

1-3) environment setup & build

$ export ARCH=arm

$ export SUBARCH=arm

$ export CROSS_COMPILE=arm-eabi-

$ make flo_defconfig

$ make -j4


http://dayntimes.tistory.com/plugin/CallBack_bootstrapperSrc?nil_profile=tistory&nil_type=copied_post

* if no error occurs, msm/arch/boot/zImage will be created.

2) making boot.img

 2-1) image generation tool download

$  git clone https://github.com/pbatard/bootimg-tools.git

$ cd bootimg-tools

$ make

$ cd mkbootimg

$ cp mkbootimg unmkbootimg tool-chain-path

 2-2) google factory image download

factory image url : https://developers.google.com/android/nexus/images#razorkot49h

 2-3) factory 에서 boot.img 추출

$ mkdir tmp

$ mkdir repack

$ cd tmp

$ wget https://dl.google.com/dl/android/aosp/razor-mob30x-factory-52684dff.zip

$ unzip razor-mob30x-factory-52684dff.zip

$ cd razor-mob30x

$ unzip image-razor-mob30x.zip

$ cp boot.img ../repack

 2-4) create new boot.img

 $ cd repack

 $ unmkbootimg -i boot.img

 kernel written to ‘kernel’ (6690056 bytes)

ramdisk written to ‘ramdisk.cpio.gz’ (492371 bytes)

To rebuild this boot image, you can use the command:

  mkbootimg –base 0 –pagesize 2048 –kernel_offset 0x80208000 –ramdisk_offset 0x82200000 –second_offset 0x81100000 –tags_offset 0x80200100 –cmdline ‘console=ttyHSL0,115200,n8 androidboot.hardware=flo user_debug=31 msm_rtb.filter=0x3F ehci-hcd.park=3’ –kernel kernel –ramdisk ramdisk.cpio.gz -o boot.img

$ cp <kernel-build-path>/msm/arch/arm/boot/zImage ./zImage

$ mkbootimg –base 0 –pagesize 2048 –kernel_offset 0x80208000 –ramdisk_offset 0x82200000 –second_offset 0x81100000 –tags_offset 0x80200100 –cmdline ‘console=ttyHSL0,115200,n8 androidboot.hardware=flo user_debug=31 msm_rtb.filter=0x3F ehci-hcd.park=3’ –kernel zImage –ramdisk ramdisk.cpio.gz -o boot.img

3. flash

$ adb reboot-bootloader

$ sudo fastboot oem unlock  (if flash is LOCKED)

$ sudo fastboot flash boot boot.img

$ sudo fastboot reboot 

4. Check update

 – Setting -About tablet – ‘Kernel version’

 

 

PS.

for kernel config file, usualy it’s located at <kernel_source>/arch/arm/configs directory

to build a kernel to match the specified target, you can extract the kernel config from the kernel Image or boot.img.

Simply usomg following command:

extract-ikconfig kernelImage

 

 

 

Ref.:

http://dayntimes.tistory.com/1278

Anroid Input Event Analysis ENG/CHN/KOR Version

android_input_stack.PNG

Input Handling at the Linux Kernel Layer

Interrupt Handling

An input event begins with an interrupt, which is generated when the device (touch screen, physical button, headphone jack, etc) detects the physical event. At the lowest level, this event causes electrical current, which is converted to an interrupt, which is delivered via the interrupt controller to the CPU, on one of the many interrupt request lines (IRQs).

Linux provides a default interrupt handler in the form of do_IRQ. This function checks if any device drivers have “claimed” the interrupt (by calling request_irq()). Usually, each driver will claim the IRQ line corresponding to its device, though it is not uncommon to see interrupt lines shared between two or more drivers. A driver claiming an IRQ also supplies a callback – often referred to as an ISR (Interrupt Service Routine), which will be invoked by do_IRQ when an interrupt is received on the claimed IRQ.

You can view the interrupt lines claimed by drivers if you look at /proc/interrupts. This highly architecture dependent file will show you the interrupt count for interrupts which have been registered (a different file, /proc/stat, will show all interrupt counts). Each interrupt line is shown with the count, controller type, and registered driver name. The driver names are often quite cryptic, but in some cases (such as the Galaxy S series) are well defined. The Galaxy S4 also shows a good example of multiple interrupt controllers, as shown in the following output, demonstrating some of the more interesting interrupts on the device:

shell@s4:/ $ cat /proc/interrupts
           CPU0       
 17:          0       GIC  dg_timer
 18:    9245245       GIC  gp_timer           # Timer interrupt 
	...
 34:          1       GIC  MSM_L2
 36:     243472       GIC  synaptics_rmi4_i2c # Touch screen
 47:          0       GIC  pm8821_sec_irq
 48:     981035       GIC  msmgpio
  ...

134:    4960502       GIC  msm-sdcc (cmd), msm-sdcc (pio)  #
135:     950126       GIC  msm-sdcc (cmd), msm-sdcc (pio)  # Flash storage
136:    4359946       GIC  msm-sdcc (cmd), msm-sdcc (pio)  #

            ...
343:        107   msmgpio  max77693-irq
351:        517   msmgpio  bluetooth hostwake      # Bluetooth devices
353:     503146   msmgpio  bcmsdh_sdmmc
362:     453332   msmgpio  pm8xxx_usr_irq
365:          0   msmgpio  sii8240
369:          0   msmgpio  sec_headset_detect      # headset jack
371:          0   msmgpio  msm_hsl_wakeup
474:          0    pm8xxx  pm8921_overtemp_irq
479:       3896    pm8xxx  pm8xxx_rtc_alarm
486:          0    pm8xxx  pm8921_batt_alarm_irq
489:          0    pm8xxx  msm_otg
490:         63    pm8xxx  pmic8xxx_pwrkey_release # Power down
491:         63    pm8xxx  pmic8xxx_pwrkey_press   # Power up
             ...

661:        579    pm8xxx  home_key                 # home button
662:       1338    pm8xxx  cypress_touchkey         # menu, back
664:          0    pm8xxx  msm-sdcc (slot)
666:         28    pm8xxx  volume_up_key            # Volume UP  
668:         56    pm8xxx  volume_down_key          # Volume DOWN
                 ...

# Inter processor (core) interrupts: Note four columns for quad-core
IPI0:          0      13962      13870      11649  CPU start interrupts
IPI1:          0          0          0          0  Timer broadcast interrupts
IPI2:    3947099    5539984    2449051    1427641  Rescheduling interrupts
IPI3:       1369      12875      12846      12533  Function call interrupts
IPI4:        402     126466     109265      91618  Single function call interrupts
IPI5:          0          0          0          0  CPU stop interrupts
IPI6:          0          0          0          0  CPU backtrace
Err:          0

In other cases, however, like the HTC One M8, the physical keys are all grouped under one interrupt, gpio_keys. Another interesting feature is that on multi-core CPUs, you will actually see multiple interrupt count columns when additional cores are active. You can further control which core responds to which interrupt by writing a hexadecimal mask value to the/proc/irq/##/smp_affinity. Advanced boards may also show “IPI” (inter-processor interrupts) as well.

You can empirically determine which IRQs are associated with which devices by viewing/proc/interrupts before and after triggering an interrupt from a device (for example, touching the screen, or pressing a button). A physical button press will usually result in 2 or more interrupts (corresponding to the button down and button up events), whereas swipes and other gestures may very well result in dozens or more, the same as mouse motion would on a desktop system.

Interrupts are effectively handled at the highest possible priority. With rare exceptions, an interrupt will preempt whichever thread is executing on the CPU, as it demands the kernel’s immediate attention. Desktop systems make use of this fact in some cases (for example, with the SysRQ mechanism), though a more immediate application is that, when a device is hanging, most users intuitively press buttons, tap, swipe, or otherwise try to “wake up” the device. In practice, this can, in theory, be detrimental, as more events trigger more interrupts, which can increase the system load by preempting what the CPU was doing, in favor of handling otherwise meaningless gestures. In practice, however, interrupt handling is so quick the load they introduce is fairly minimal.

Well behaved drivers obey the strict requirements of handling IRQs – they never block, and take as little time as possible, deferring work toa software IRQ (the kernel’s ksoftirq threads). Interrupts therefore usually have minimal effects on the system. In addition some devices can use tricks such as interrupt coalescing (firing one interrupt instead of several), and devices will not fire interrupts when the device is sleeping (for example, the touch screen, when the display is turned off).

The Linux Input Driver Model

Android uses the standard Linux input driver model, introduced back in 2.4 and standardized in 2.6 and later. The Linux kernel documentation contains a subdirectory documenting the model and usage of its programming interfaces (Documentation/input/, and in particular input.txt). The interested reader is encouraged to consult the documentation for more detail, though we provide an overview in this section.

A device driver responsible for an input device is required to allocate an input_dev structure and populate its capabilties. This structure is defined in <linux/input.h> and shown in figure figInputDev, along with the ioctl(2) codes which can be used to retrieve selected fields from user mode:

field contains ioctl(2) code
name device display name EVIOCGNAME
phys device physical path in /sys EVIOCGPHYS
uniq unique code, if any EVIOCGUNIQ
id struct input_id
propbit device properties and quirks EVIOCGPROP
evbit EV_ event types supported by device
keybit keys/buttons this device has EVIOCGBIT(EV_KEY..)
relbit relative axes for the device EVIOCGBIT(EV_REL..)
absbit absolute axes for the device EVIOCGBIT(EV_ABS..)
mscbit miscellaneous events supported by device EVIOCGBIT(EV_MSC..)
ledbit LEDs present on the device EVIOCGBIT(EV_LED..)
sndbit sound effects supported by device EVIOCGBIT(EV_SND..)
ffbit supported force feedback effects, if any EVIOCGBIT(EV_FF..)
swbit switches present on the device EVIOCGBIT(EV_SW..)
hint_events_per_packet average # of events generated by device
keycodemax size of keycode table
keycodesize size of elements in keycode table
keycode map of scancodes to keycodes for device
getkeycode (legacy) retrieve current keymap.
ff Force-Feedback, if any
repeat_key Last pressed key, for auto-repeat
timer auto-repeat timer
rep auto-repeat parameters
mt struct input_mt holding Multitouch state
absinfo Absolute axes coordinate information
key current state of device keys/buttons EVIOCGKEY
led current state of device LEDs, if any EVIOCGLED
sw current state of device switches, if any EVIOCGSW
open callback for open(2) on device
close callback for close(2) on device
flush flush device events,e.g. force-feedback
event handler for events sent to device
Figure figInputDev: The struct input_dev (from <linux/input.h>)

The input driver registers its input_devs with the kernel input manager by a call toinput_device_register. Doing so will automatically create a sysfs entries (symbolic links) for the device in /sys/class/input, and character device entries, which in turn will be picked up by Linux’sudevd (or Android’s ueventd) to create corresponding /dev/input/event## entries. The character device node is registered under the major of the input manager, with a minor corresponding to its order of registration + 64 (e.g. event0 would have minor 64, event1 would have minor 65, etc). Operations on the created device node will be handled by an evdev_fops file_operations structure (in <drivers/input/evdev.c>), with generic blocking implementations for read, write, poll, etc.

As shown in the figure, the key fields of the input_dev structure are accessible via standardioctl(2) calls with specific EVIOC* constants. Additionally, the capabilties and properties of a device are exported to user mode via entries in sysfs, under /sys/class/input/event##/device/capabilities/and /sys/class/input/event##/device/properties.

The Linux device drivers respond to interrupts, generated by the respective devices. The drivers then report the events using the input_report_[key/...] functions, and events are then queued onto the /dev/input/event## device as structs containing the timestamp, event type, associated code and value. User mode applications use the standard system calls (that is read(2),select(2)/poll(2) and the like) to retrieve events (always an integer multiple ofsizeof(input_event)) from the device. The supported event types are defined in <input/event.h>and shown in table 11-evttypes:

# Event code Specifies
0x00 EV_SYN Separate/synchronize other events (e.g. SYN_REPORT/SYN_MT_REPORT), or report events lost (SYN_DROPPED)
0x01 EV_KEY Key press (KEY_*) or touch (BTN_TOUCH)
0x02 EV_REL Relative changes to a property. Changes relayed through REL_[XYZ] values.
0x03 EV_ABS Absolute coordinates for an event. Values are usually ABS_[XYZ], or ABS_MT for multi-touch
0x04 EV_MSC Miscellaneous codes
0x05 EV_SW Binary switches. E.g. SW_JACK_PHYSICAL_INSERT for headphone insertion
0x11 EV_LED Used for device LEDs, if any
0x12 EV_SND Used for sound devices
0x14 EV_REP Used for auto-repeating events
0x15 EV_FF Used for force-feedback capable devices (e.g. joysticks). An EVIOCSFF ioctl may be used to upload force feedback effects
0x16 EV_PWR Reserved for power events. Largely unused
0x17 EV_FF_STATUS Used for force-feedback capable devices.

Naturally, not all input devices support all event classes; The input_dev structure maps the various events a particular device supports by its bitmaps, and the device’s sysfs entry makes those bitmaps visible in user mode as /sys/class/input/inputXX/capabilities. The input event source of each device is in /sys/class/input/inputXX/eventXX, and also conveniently symlinked directly from/sys/class/input.

Note, that even though the Linux input model was designed for HID type devices, it can be used on virtually any devices, including sensors. This is shown in the following experiment.

Experiment: Looking at low-level input eventsYou can examine input events yourself through the shell. First, look at the files in /dev/input. On the emulator, you should see something like this:


root@generic:/ # ls -l /dev/input
crw-rw---- root     input     13,  64 2013-11-15 18:24 event0
crw-rw---- root     input     13,  63 2013-11-15 18:24 mice
crw-rw---- root     input     13,  32 2013-11-15 18:24 mouse0

Output on a real device will likely be different, as these have many more input channels, mapped to its various sensors; The Samsung S3, for example, has event0 through event13, and no “mouse0”. The major and minor numbers, however, should be the same, and the major (13) is associated with the kernel input driver subsystems (as can be verified with grep input /proc/devices).The system keeps track of all devices quite conveniently in /proc/bus/input/devices:


shell@htc_m8wl:/ $ cat /proc/bus/input/devices 
I: Bus=0000 Vendor=0000 Product=0000 Version=0000
N: Name="h2w headset"
P: Phys=
S: Sysfs=/devices/virtual/input/input6
U: Uniq=
H: Handlers=kbd event6 keychord 
B: PROP=0
B: EV=3
B: KEY=84 10000 138 0 e0800 0 0 0
..

To see the properties and capabilities of a given device, say /dev/input/event0, examine its sysfs entry:


## File sizes are reported as 4k (pagesize) arbitrarily - all virtual anyway
shell@generic:/sys/class/input/event0$ ls -l
-r--r--r-- root  root 4096  2013-11-15 18:24 dev
lrwxrwxrwx root  root       2013-11-15 18:24 device -> ../../input0
drwxr-xr-x root  root       2013-11-15 18:24 power
lrwxrwxrwx root  root       2013-11-15 18:24 subsystem -> ../../../../../class/input
-rw-r--r-- root  root 4096  2013-11-15 18:24 uevent
root@generic:/sys/class/input/event0 # cat uevent
MAJOR=13
MINOR=64
DEVNAME=input/event0

By accessing the device nodes, you can treat the input sources as files, and by using a command such as “cat” on them, dump raw events directly to standard output, though those would be appear to be nothing more than synchronized garbage. A better way would be to use the getevent command, which is part of toolbox. The source for this tool is atsystem/core/toolbox/getevent.c.

When used as getevent, toolbox invokes getevent_main(), which uses Linux’s inotify to enumerate the files in /dev/input/event. It then opens each detected device, and uses the ioctls from the previous table to obtain the device information. Finally, it adds the device to an array of file descriptors which it polls continuously. As each device (event source) signals input, geteventreads the event records and dumps it to stdout.

getevent has several particularly useful switches:

  • -i: Show HID codes and other information
  • -l: Show numbers in human readable constant form (e.g. “0001” as KEY_ESC)
  • -p: Show device capabilities (as per sysfs capabilities file) and exit
  • -t: Show timestamps
  • -h: Show help on all switches (-n, -t, -s, -S, -v, -d, -p, -i, -l, -q, -c and -r) then exit
Experiment: Looking at low-level input events (cont.)Armed with this information, you can conduct this simple experiment: Make sure your display isn’t sleeping, then run getevent -l via adb on your device (or emulator), and then touch the screen. On the emulator, you should see output similar to the following:


shell@generic:/$ getevent -l
could not get driver version for /dev/input/mouse0, Not a typewriter
add device 1: /dev/input/event0
  name:     "qwerty2"
could not get driver version for /dev/input/mice, Not a typewriter
/dev/input/event0: EV_ABS  ABS_X                00000083 # X position of touch
/dev/input/event0: EV_ABS  ABS_Y                00000129 # Y position of touch
/dev/input/event0: EV_KEY  BTN_TOUCH            DOWN     # Touch start       
/dev/input/event0: EV_SYN  SYN_REPORT           00000000 # Event "terminator"
/dev/input/event0: EV_KEY  BTN_TOUCH            UP       # Touch end
/dev/input/event0: EV_SYN  SYN_REPORT           00000000 # Event "terminator" 

On a real device (for example, the Samsung S3) you’ll see much more output, owing to the myriad input sources it has. The msm8960 sensors, for example, are what enables headphone vendors to control music playing and call answering through the headphone jack.


shell@s3:/$ getevent -l
## getevent will display all enumerated devices:
add device 1: /dev/input/event6   name:     "sec_touchscreen"
add device 2: /dev/input/event8   name:     "barometer_sensor"
add device 3: /dev/input/event4   name:     "sec_jack"
add device 4: /dev/input/event3   name:     "light_sensor"
add device 5: /dev/input/event2   name:     "proximity_sensor"
add device 6: /dev/input/event0   name:     "sii9234_rcp"
add device 7: /dev/input/event12  name:     "msm8960-snd-card Headset Jack"
add device 8: /dev/input/event11  name:     "msm8960-snd-card Button Jack"
add device 9: /dev/input/event10  name:     "msm8960-snd-card Volumeup Jack"
add device 10: /dev/input/event9  name:     "msm8960-snd-card Volumedown Jack"
add device 11: /dev/input/event13 name:     "sec_touchkey"
add device 12: /dev/input/event1  name:     "fsa9485"       
add device 13: /dev/input/event5  name:     "sec_keys"         # physical keys
add device 14: /dev/input/event7  name:     "sec_powerkey"     # power button - KEY_POWER
# These are sent regularly from the light sensor, as it's highly sensitive
/dev/input/event3: EV_REL  REL_X                00000020            
/dev/input/event3: EV_REL  REL_Y                00000021            
/dev/input/event3: EV_REL  REL_Z                00000015            
/dev/input/event3: EV_REL  REL_MISC             00000024            
/dev/input/event3: EV_SYN  SYN_REPORT           00000000            
## Touch event: Notice ABS_MT is used here, rather than BTN_TOUCH
/dev/input/event6: EV_ABS  ABS_MT_TRACKING_ID   00000043 # unique ID for this touch           
/dev/input/event6: EV_ABS  ABS_MT_WIDTH_MAJOR   0000000a # major axis of approaching ellipse           
/dev/input/event6: EV_ABS  ABS_MT_POSITION_X    0000011f # center x touch position          
/dev/input/event6: EV_ABS  ABS_MT_POSITION_Y    0000022d # center y touch position
/dev/input/event6: EV_ABS  ABS_MT_TOUCH_MAJOR   00000010 # major axis of touch ellipse
/dev/input/event6: EV_ABS  ABS_MT_TOUCH_MINOR   0000000c # minor axis of touch ellipse
/dev/input/event6: EV_ABS  ABS_MT_TOOL_X        ffffffc4 # center y tool position
## Physical buttons: HOME and VOLUMEDOWN together (notice /dev/input/event5)
/dev/input/event5: EV_KEY  KEY_VOLUMEDOWN       DOWN         
/dev/input/event5: EV_SYN  SYN_REPORT           00000000       
/dev/input/event5: EV_KEY  KEY_HOMEPAGE         DOWN                
/dev/input/event5: EV_SYN  SYN_REPORT           00000000       
/dev/input/event5: EV_KEY  KEY_VOLUMEDOWN       UP         
/dev/input/event5: EV_SYN  SYN_REPORT           00000000       
/dev/input/event5: EV_KEY  KEY_HOMEPAGE         UP
/dev/input/event5: EV_SYN  SYN_REPORT           00000000       

Experiment: Simulating low-level events with sendeventAs it so happens, toolbox also has a sendevent tool which you can use to simulate events at the lowest level, by writing directly to the /dev/input/eventXX device nodes. The code itself isstraightforward, constructing an input_event from the command line, and calling write(2) to send it to the device node. The caller needs write access to the device node – which the shell provides for you even on non-rooted device thanks to its group membership in the input group.

Using this tool alongside getevent brings out the real usefulness of low-level UI Automation: With getevent, you can record input events – touch, swipe, and physical button events on most devices, but even sensor readings like orientation, proximity and light (on those devices which support it, like the Samsung S3, above). You can then replay them with sendevent. There are only two caveats to remember:

  1. While getevent spits out the events in hexadecimal, sendevent will expect decimal input. So you will have to do the conversion yourself (or use a simple script to do so)
  2. Most events, though atomic to the user, are broken up into multiple components, and require the SYN_REPORT synthetic event to act as a delimiter. It’s therefore important to send that event at the end of the sequence.

The following example shows a simulation of pressing the home button on an S3. since the EV_KEY constants are the same across Linux (and Android) versions, the only adaptation required for other devices would be the figuring out which /dev/input/eventXX node to use. Continuing the previous output, we would have something like:


# simulate EV_KEY KEYHOMEPAGE DOWN followed by REPORT
shell@s3$ sendevent /dev/input/event5 1 172 1; sendevent /dev/input5 0 0 0
# To simulate home button hold, delay the following line, simulating the UP/REPORT
shell@s3$ sendevent /dev/input/event5 1 172 0; sendevent /dev/input5 0 0 0 

As we continue traversing up the input stack, the next experiment you encounter will introduce you to yet another method of simulating input events.

————————————————–
CHN Version:

 Android 中input event的分析

Android 系统里面有很多小工具,运行这些工具,我们对它们有一个感性的认识,进而阅读和分析这些小工具源代码,再顺藤摸瓜,就可以把整个子系统的来龙去脉弄清楚。

1.运行toolbox的getevent 工具。

# getevent -help
getevent -help
Usage: getevent [-t] [-n] [-s switchmask] [-S] [-v [mask]] [-p] [-q] [-c count] [-r] [device]
-t: show time stamps
-n: don’t print newlines
-s: print switch states for given bits
-S: print all switch states
-v: verbosity mask (errs=1, dev=2, name=4, info=8, vers=16, pos. events=32)
-p: show possible events (errs, dev, name, pos. events)
-q: quiet (clear verbosity mask)
-c: print given number of events then exit
-r: print rate events are received
# getevent -c 20
getevent -c 20
add device 1: /dev/input/event4
name:     “sensor-input”
add device 2: /dev/input/event3
name:     “88pm860x_hook”
add device 3: /dev/input/event2
name:     “88pm860x_on”
add device 4: /dev/input/event1
name:     “88pm860x-touch”
add device 5: /dev/input/event0
name:     “pxa27x-keypad”

运行这个工具,然后按键或者滑动触摸屏,会看到程序会实时打印event。从上面的输出来看,系统有5个input 子系统。它们分别是

add device 1: /dev/input/event4
name:     “sensor-input”

#Sensor input 子系统

add device 2: /dev/input/event3
name:     “88pm860x_hook”

#耳机Hook键子系统。可支持接电话挂电话的耳机上面有一个按键,对应的就是这个input 子系统。

add device 3: /dev/input/event2
name:     “88pm860x_on”

#开机键 input 子系统
add device 4: /dev/input/event1
name:     “88pm860x-touch”

#Touch Screen input 子系统
add device 5: /dev/input/event0
name:     “pxa27x-keypad”

#按键子系统,包括Home/Menu/Back等按键。

可以尝试多种event,实际感觉一下出来的log。

 

2.阅读getevent的代码。代码为./core/toolbox/getevent.c

从代码中,我们知道,程序在while(1)的一个死循环里,不断地在读取 (select 操作)/dev/input 下面的文件,检查是否Kernel往里面更新内容,如果有内容更新,就把它打印出来。并且从代码中,我们还知道,任何一个event都有三种属性,type,code,value.

while(1) {
        pollres = poll(ufds, nfds, -1);
//printf(“poll %d, returned %d/n”, nfds, pollres);
if(ufds[0].revents & POLLIN) {
read_notify(device_path, ufds[0].fd, print_flags);
}
for(i = 1; i < nfds; i++) {
if(ufds[i].revents) {
if(ufds[i].revents & POLLIN) {
                    res = read(ufds[i].fd, &event, sizeof(event));
if(res < (int)sizeof(event)) {
fprintf(stderr, “could not get event/n”);
return 1;
}
if(get_time) {
printf(“%ld-%ld: “, event.time.tv_sec, event.time.tv_usec);
}
if(print_device)
printf(“%s: “, device_names[i]);
                    printf(“%04x %04x %08x”, event.type, event.code, event.value);

if(sync_rate && event.type == 0 && event.code == 0) {
int64_t now = event.time.tv_sec * 1000000LL + event.time.tv_usec;
if(last_sync_time)
printf(” rate %lld”, 1000000LL / (now – last_sync_time));
last_sync_time = now;
}
printf(“%s”, newline);
if(event_count && –event_count == 0)
return 0;
}
}
}

3.问题来了,Android Framework是否也是一样的原理呢??猜测应该是一样的才对,不然这个工具就没有调试的价值了。

我们来阅读和分析framework中input event的相关代码。

我们从Kernel层往上看,先看看Framework中,直接操纵/dev/input设备的代码。

在.frameworks/base/libs/ui/EventHub.cpp 中,我们看到跟getevent工具类似的代码。

bool EventHub::getEvent(int32_t* outDeviceId, int32_t* outType,
int32_t* outScancode, int32_t* outKeycode, uint32_t *outFlags,
int32_t* outValue, nsecs_t* outWhen)
{

….

while(1) {
….
release_wake_lock(WAKE_LOCK_ID);

        pollres = poll(mFDs, mFDCount, -1);

acquire_wake_lock(PARTIAL_WAKE_LOCK, WAKE_LOCK_ID);

if (pollres <= 0) {
if (errno != EINTR) {
LOGW(“select failed (errno=%d)/n”, errno);
usleep(100000);
}
continue;
}

….

// mFDs[0] is used for inotify, so process regular events starting at mFDs[1]
for(i = 1; i < mFDCount; i++) {
if(mFDs[i].revents) {
LOGV(“revents for %d = 0x%08x”, i, mFDs[i].revents);
if(mFDs[i].revents & POLLIN) {
                    res = read(mFDs[i].fd, &iev, sizeof(iev));
if (res == sizeof(iev)) {
LOGV(“%s got: t0=%d, t1=%d, type=%d, code=%d, v=%d”,
mDevices[i]->path.string(),

….

}

4.那么framework中那个模块再调用EventHub呢,接着往下查。

在framework目录中,输入下面的命令查找

# find . -name “*.cpp” |grep -v EventHub | xargs grep EventHub
./base/services/jni/com_android_server_KeyInputQueue.cpp:#include <ui/EventHub.h>
./base/services/jni/com_android_server_KeyInputQueue.cpp:static sp<EventHub> gHub;
./base/services/jni/com_android_server_KeyInputQueue.cpp:    sp<EventHub> hub = gHub;
./base/services/jni/com_android_server_KeyInputQueue.cpp:        hub = new EventHub;
./base/services/jni/com_android_server_KeyInputQueue.cpp:    sp<EventHub> hub = gHub;
./base/services/jni/com_android_server_KeyInputQueue.cpp:        hub = new EventHub;

5.从查找结果中得知,在jni文件com_android_server_KeyInputQueue.cpp文件中有对EventHub进行调用。

打开并阅读com_android_server_KeyInputQueue.cpp文件得知,在下面的函数中调用了EventHub的getEvent函数

static jboolean
android_server_KeyInputQueue_readEvent(JNIEnv* env, jobject clazz,
jobject event)
{
gLock.lock();
sp<EventHub> hub = gHub;
if (hub == NULL) {
hub = new EventHub;
gHub = hub;
}
gLock.unlock();

int32_t deviceId;
int32_t type;
int32_t scancode, keycode;
uint32_t flags;
int32_t value;
nsecs_t when;
    bool res = hub->getEvent(&deviceId, &type, &scancode, &keycode,
&flags, &value, &when);

env->SetIntField(event, gInputOffsets.mDeviceId, (jint)deviceId);
env->SetIntField(event, gInputOffsets.mType, (jint)type);
env->SetIntField(event, gInputOffsets.mScancode, (jint)scancode);
env->SetIntField(event, gInputOffsets.mKeycode, (jint)keycode);
env->SetIntField(event, gInputOffsets.mFlags, (jint)flags);
env->SetIntField(event, gInputOffsets.mValue, value);
env->SetLongField(event, gInputOffsets.mWhen,
(jlong)(nanoseconds_to_milliseconds(when)));

return res;
}

6.根据jni的调用规则,在本文件中查找对于的Java函数。

static JNINativeMethod gInputMethods[] = {

/* name, signature, funcPtr */
{ “readEvent”,       “(Landroid/view/RawInputEvent;)Z”,
(void*) android_server_KeyInputQueue_readEvent },

….

7. 接着顺藤摸瓜,找到对应的java文件,base/services/java/com/android/server/KeyInputQueue.java

private static native boolean readEvent(RawInputEvent outEvent);

在一个线程中会调用readEvent函数。

Thread mThread = new Thread(“InputDeviceReader”) {
public void run() {
if (DEBUG) Slog.v(TAG, “InputDeviceReader.run()”);
android.os.Process.setThreadPriority(
android.os.Process.THREAD_PRIORITY_URGENT_DISPLAY);

RawInputEvent ev = new RawInputEvent();
while (true) {
try {
InputDevice di;

                    // block, doesn’t release the monitor
readEvent(ev);

boolean send = false;
boolean configChanged = false;

if (false) {
Slog.i(TAG, “Input event: dev=0x”
+ Integer.toHexString(ev.deviceId)
+ ” type=0x” + Integer.toHexString(ev.type)
+ ” scancode=” + ev.scancode
+ ” keycode=” + ev.keycode
+ ” value=” + ev.value);
}

 

8.那是谁启动这个线程呢???查找mThread变量,得知在KeyInputQueue的构造函数中会启动这个线程。

 

    KeyInputQueue(Context context, HapticFeedbackCallback  hapticFeedbackCallback) {
if (MEASURE_LATENCY) {
lt = new LatencyTimer(100, 1000);
}

Resources r = context.getResources();
BAD_TOUCH_HACK = r.getBoolean(com.android.internal.R.bool.config_filterTouchEvents);

JUMPY_TOUCH_HACK = r.getBoolean(com.android.internal.R.bool.config_filterJumpyTouchEvents);

mHapticFeedbackCallback = hapticFeedbackCallback;

readExcludedDevices();

PowerManager pm = (PowerManager)context.getSystemService(
Context.POWER_SERVICE);
mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
“KeyInputQueue”);
mWakeLock.setReferenceCounted(false);

mFirst = new QueuedEvent();
mLast = new QueuedEvent();
mFirst.next = mLast;

        mThread.start();
}

9.那这个KeyInputQueue是在哪里被实例化呢?

而且查看KeyInputQueue类的声明,得知它是一个abstract class.

public abstract class KeyInputQueue

{

…..

}

说明它肯定会被某个类继承.接着查找。

/frameworks$ find . -name “*.java” |grep -v KeyInputQueue | xargs grep KeyInputQueue
./policies/base/phone/com/android/internal/policy/impl/KeyguardViewMediator.java: * {@link com.android.server.KeyInputQueue}’s and {@link android.view.WindowManager}’s.
./base/services/java/com/android/server/PowerManagerService.java:                    && !”KeyInputQueue”.equals(tag))) {
./base/services/java/com/android/server/WindowManagerService.java:import com.android.server.KeyInputQueue.QueuedEvent;
./base/services/java/com/android/server/WindowManagerService.java:        implements Watchdog.Monitor, KeyInputQueue.HapticFeedbackCallback {
./base/services/java/com/android/server/WindowManagerService.java:        return KeyInputQueue.getSwitchState(sw);
./base/services/java/com/android/server/WindowManagerService.java:        return KeyInputQueue.getSwitchState(devid, sw);
./base/services/java/com/android/server/WindowManagerService.java:        return KeyInputQueue.hasKeys(keycodes, keyExists);
./base/services/java/com/android/server/WindowManagerService.java:    private class KeyQ extends KeyInputQueue
./base/services/java/com/android/server/WindowManagerService.java:            implements KeyInputQueue.FilterCallback {
./base/services/java/com/android/server/InputDevice.java:    // For use by KeyInputQueue for keeping track of the current touch
./base/services/java/com/android/server/InputDevice.java:            if (KeyInputQueue.BAD_TOUCH_HACK) {
./base/services/java/com/android/server/InputDevice.java:                    Slog.i(“KeyInputQueue”, “Updating: ” + currentMove);
./base/services/java/com/android/server/InputDevice.java:                    Slog.i(“KeyInputQueue”, “Updating: ” + currentMove);

10.从上面的查找结果得知,会在WindowManagerService.java中有一个KeyQ类继承KeyInputQueue类,再在这个文件中查找KeyQ类在哪里定义并实例化的,找到在其构造函数里实例化的。

   private WindowManagerService(Context context, PowerManagerService pm,
boolean haveInputMethods) {
if (MEASURE_LATENCY) {
lt = new LatencyTimer(100, 1000);
}

….

    mQueue = new KeyQ();

mInputThread = new InputDispatcherThread();

PolicyThread thr = new PolicyThread(mPolicy, this, context, pm);

}

至此,基本上把Input event的Framework的流程全部走完了。WindowManagerService是属于System server进程里面起的一个Service.一开机就会运行,当然其构造函数一开机就能会运行。

至此,整个流程如下:

    WindowManagerService

                             |

                             |

                            //

                         KeyQ

                             |

                             |

                            //

                        KeyInputQueue

                             |

                             |

                            //

                        EventHub

                             |

                             |

                            //

                         Kernel device (/dev/input)

 


KOR Version.

1. Input Device 개요

1.1 리눅스 2.6에서 Input Device Driver 특징

커털 2.4에서 사용하던 카테고리별 입력장치를 표준화하여 하나의 인터페이스로 통일화했다.

1.2 Input Device Driver 구조

– Device Driver : 하드웨어의 입력을 처리

– Event Handler : 입력 정보를 애플리케이션에게 전달

1.3 Device Driver가 응용프로그램으로 데이터를 올리는 방법 (Event Handler)

– include/linux/input.h

struct input_event : 이 구조체를 이용해서 데이터를 응용프로그램으로 전달함

struct input_event {

struct timeval time;

__u16 type;

__u16 code;

__s32 value;

};

/* Event types */

#define EV_SYN 0x00    : event synchronize, 커널의 드라이버와 으용프로그램 간의 동기화

#define EV_KEY 0x01    : pen down과 pen up 이벤트 등이 있음

#define EV_REL 0x02    : mouse와 같은 상대좌표 특성

#define EV_ABS 0x03    : 절대값 좌표 전달 (ABS_X, ABS_Y 등)

#define EV_SW 0x05    : switch event

ex) touchscreen : EV_SYN | EV_ABS | EV_KEY

접기

1.4 Input Device Driver에 등록된 event interface와 디바이스 정보 확인

– proc 파일시스템 이용

/proc/bus/input/devices : 현재 시스템에 연결되어 있는 디바이스.

접기

/proc/bus/input/devices

I : Information, 디바이스의 정보 중 연결된 버스 번호, 생산자 ID, 제품 ID, 버전을 보여준다.

N : Name, 디바이스 이름을 알려준다. (안드로이드에서 키보드 포팅할 때 중요한 역할을 한다.)

P : Physical, 내부적으로 표현되는 물리적인 장치 이름을 가리킨다.

H : Handler, 이 device driver와 연결되어 동작하는 디바이스 파일 노드가 어떤 것인지를 표현한다.

S : System File, /sys 디렉토리의 어느 것을 사용하는지에 대한 값을 얻을 수 있다.

B : Bit Mask Info, evbit와 keybit와 같이 장치의 타입을 알 수 있다.

접기

/dev/input/* : event interface 장치

응용프로그램에서 event 디바이스 파일을 열어서 디바이스의 특성을 ioctl로 파악한 후, 적절한 입력장치로부터 데이터를 입력받는다.

1.5 Input Device가 적절하게 데이터를 전달하는지 확인하는 코드 aesopev.c

– key input test : ./aesopev key

– touch test : ./aesopev touch

2. 안드로이드 Input Device Driver

2.1 안드로이드 Input Device 예

– keyboard : /dev/input/event0

– Touchscreen : /dev/input/event1

– Switch driver : /dev/input/event2

2.2 안드로이드 Key Driver

2.2.1 안드로이드는 커널에서 올라오는 입력장치를 EventHub에서 처리하고, 안드로이드의 key layout file과 비교한 후, 애플리케이션 Framework 쪽으로 해당 키 값을 올려준다.

-키보드의 키에 할당되어 있는 key scancode 값 확인

– include/linux/input.h

접기

#define KEY_BOOKMARKS           156     /* AC Bookmarks */

#define KEY_COMPUTER            157

#define KEY_BACK                158     /* AC Back */

#define KEY_FORWARD             159     /* AC Forward */

접기

– drivers/input/keyboard/s3c-keypad.c

– 안드로이드로 올라가는 keycode 값 확인

– 안드로이드 Rootfs/system/usr/keylayout/qwerty.kl

접기

// key | scancode | keycode | flags

key 158   BACK              WAKE_DROPPED

key 230   SOFT_RIGHT        WAKE

key 60    SOFT_RIGHT        WAKE

key 107   ENDCALL           WAKE_DROPPED

key 62    ENDCALL           WAKE_DROPPED

key 229   MENU              WAKE_DROPPED

key 139   MENU              WAKE_DROPPED

key 59    MENU              WAKE_DROPPED

key 127   SEARCH            WAKE_DROPPED

key 217   SEARCH            WAKE_DROPPED

key 228   POUND

key 227   STAR

key 231   CALL              WAKE_DROPPED

key 61    CALL              WAKE_DROPPED

key 232   DPAD_CENTER       WAKE_DROPPED

key 108   DPAD_DOWN         WAKE_DROPPED

key 103   DPAD_UP           WAKE_DROPPED

key 102   HOME              WAKE

key 105   DPAD_LEFT         WAKE_DROPPED

key 106   DPAD_RIGHT        WAKE_DROPPED

key 115   VOLUME_UP         WAKE

key 114   VOLUME_DOWN       WAKE

key 116   POWER             WAKE

key 212   CAMERA

접기

– keycode와 flag 선언 : 안드로이드/frameworks/base/include/ui/KeycodeLabels.h

– KeyLatoutMap 클래스 : 안드로이드/frameworks/base/libs/ui/KeyLayoutMap.h와 KeyLayoutMap.cpp에 정의됨.

2.3 안드로이드 Touchscreen Driver

2.3.1 Touch Panel Device Driver 동작 절차

– X-Window : Touch Device > ADC > Device Driver > TS Lib > X-Windows

– 안드로이드 : Touch Device > ADC > Device Driver > Android

안드로이드는 device driver에서 안드로이드 시스템으로 직접 리포팅하여 터치스크린 입력을 처리한다.

2.4 안드로이드 Switch Event Device Driver 등록 방법

Input Device Driver 중 EV_SW(Switch Event) 타입을 갖는 device driver로 작성해야 함.

– include/linux/input.h

접기

/*

* Switch events

*/

#define SW_LID                  0x00  /* set = lid shut */

#define SW_TABLET_MODE          0x01  /* set = tablet mode */

#define SW_HEADPHONE_INSERT     0x02  /* set = inserted */

#define SW_RFKILL_ALL           0x03  /* rfkill master switch, type “any”

set = radio enabled */

#define SW_RADIO                SW_RFKILL_ALL   /* deprecated */

#define SW_MICROPHONE_INSERT    0x04  /* set = inserted */

#define SW_DOCK                 0x05  /* set = plugged into dock */

#define SW_LINEOUT_INSERT       0x06  /* set = inserted */

#define SW_JACK_PHYSICAL_INSERT 0x07  /* set = mechanical switch set */

#define SW_VIDEOOUT_INSERT      0x08  /* set = inserted */

#define SW_CAMERA_LENS_COVER    0x09  /* set = lens covered */

#define SW_KEYPAD_SLIDE         0x0a  /* set = keypad slide out */

#define SW_FRONT_PROXIMITY      0x0b  /* set = front proximity sensor active */

#define SW_MAX                  0x0f

#define SW_CNT                  (SW_MAX+1)

/*

접기

– SW_LID 이벤트가 발생할 수 있도록 적절하게 코드를 작성해야 한다.

interrupt 처리 함수

접기

static irqreturn_t sw_lid_keyevent(int irq, void *dev_id)

{

int switch_open_detected = 0;
http://muyu.tistory.com/plugin/CallBack_bootstrapperSrc?nil_profile=tistory&nil_type=copied_post

switch_open_detected = read_gpio_lid();

if(switch_open_detected)

{

input_report_switch(torbreck_switchbut_private_t->input, SW_LID, 1);

}

else

{

input_report_switch(torbreck_switchbut_private_t->input, SW_LID,0);

}

return IRQ_HANDLED;

}

접기

input device driver 등록 함수

접기

중요 코드

seb_bit(EV_SW, input_dev->swbit);

input_set_capability(input_dev, EV_SW, SW_LID);

접기

– 최종적으로 PhoneWindowManager.java로 올라가 필요 동작을 하도록 코드를 작성한다.

3. 안드로이드 Input Manager

3.1 안드로이드 Input Device 처리 구조

Kernel > EventHub > NativeInputManager – JNI > InputManager > WindowManager > PhoneWindowManager

① frameworks/base/services/java/com/android/server/WindowManagerService.java – Framework

② frameworks/base/services/java/com/android/server/InputManager.java – Framework

③ frameworks/base/services/jni/com_android_server_InputManager.cpp – JNI

④ frameworks/base/libs/ui/InputManager.cpp – Native

– InputManager ~ Native 함수까지 시작 호출 과정정

① WindowManagerService.jave

접기

private WindowManagerService(Context context, PowerManagerService pm,

boolean haveInputMethods) {

mContext = context;

mHaveInputMethods = haveInputMethods;

mLimitedAlphaCompositing = context.getResources().getBoolean(

com.android.internal.R.bool.config_sf_limitedAlpha);

mPowerManager = pm;

mPowerManager.setPolicy(mPolicy);

PowerManager pmc = (PowerManager)context.getSystemService(Context.POWER_SERVICE);

mScreenFrozenLock = pmc.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,

“SCREEN_FROZEN”);

mScreenFrozenLock.setReferenceCounted(false);

mActivityManager = ActivityManagerNative.getDefault();

mBatteryStats = BatteryStatsService.getService();

// Get persisted window scale setting

mWindowAnimationScale = Settings.System.getFloat(context.getContentResolver(),

Settings.System.WINDOW_ANIMATION_SCALE, mWindowAnimationScale);

mTransitionAnimationScale = Settings.System.getFloat(context.getContentResolver(),

Settings.System.TRANSITION_ANIMATION_SCALE, mTransitionAnimationScale);

// Track changes to DevicePolicyManager state so we can enable/disable keyguard.

IntentFilter filter = new IntentFilter();

filter.addAction(DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED);

mContext.registerReceiver(mBroadcastReceiver, filter);

mHoldingScreenWakeLock = pmc.newWakeLock(PowerManager.SCREEN_BRIGHT_WAKE_LOCK,

“KEEP_SCREEN_ON_FLAG”);

mHoldingScreenWakeLock.setReferenceCounted(false);

mInputManager = new InputManager(context, this);

PolicyThread thr = new PolicyThread(mPolicy, this, context, pm);

thr.start();

synchronized (thr) {

while (!thr.mRunning) {

try {

thr.wait();

} catch (InterruptedException e) {

}

}

}

mInputManager.start();

// Add ourself to the Watchdog monitors.

Watchdog.getInstance().addMonitor(this);

}

접기

② InputManager.java

접기

public void start() {

Slog.i(TAG, “Starting input manager”);

nativeStart();

}

접기

③ com_android_server_InputManager.cpp

접기

static void android_server_InputManager_nativeStart(JNIEnv* env, jclass clazz) {

if (checkInputManagerUnitialized(env)) {

return;

}

status_t result = gNativeInputManager->getInputManager()->start();

if (result) {

jniThrowRuntimeException(env, “Input manager could not be started.”);

}

}

접기

④ InputManager.cpp

접기

status_t InputManager::start() {

status_t result = mDispatcherThread->run(“InputDispatcher”, PRIORITY_URGENT_DISPLAY);

if (result) {

LOGE(“Could not start InputDispatcher thread due to error %d.”, result);

return result;

}

result = mReaderThread->run(“InputReader”, PRIORITY_URGENT_DISPLAY);

if (result) {

LOGE(“Could not start InputReader thread due to error %d.”, result);

mDispatcherThread->requestExit();

return result;

}

return OK;

}

접기

3.3 InputReader 클래스와 InputDispatcher 클래스

3.3.1 InputReader 클래스 처리 순서

Input Device에 의해 들어온 데이터를 읽어와서 처리하는 클래스다.

1) InputManger.cpp – start()에서 run()함수 호출

접기

status_t InputManager::start() {

status_t result = mDispatcherThread->run(“InputDispatcher”, PRIORITY_URGENT_DISPLAY);

if (result) {

LOGE(“Could not start InputDispatcher thread due to error %d.”, result);

return result;

}

result = mReaderThread->run(“InputReader”, PRIORITY_URGENT_DISPLAY);

if (result) {

LOGE(“Could not start InputReader thread due to error %d.”, result);

mDispatcherThread->requestExit();

return result;

}

return OK;

}

접기

2)  InputReader.cpp – InputReaderThread에서 loopOnce()함수 수행

접기

bool InputReaderThread::threadLoop() {

mReader->loopOnce();

return true;

}

접기

3) InputReader.cpp – loopOnce에서 mEventHub 객체를 통해 getEvent() 함수를 호출하여 이벤트 데이터를 가져오고 process() 함수를 호출한다.

접기

void InputReader::loopOnce() {

RawEvent rawEvent;

mEventHub->getEvent(& rawEvent);

#if DEBUG_RAW_EVENTS

LOGD(“Input event: device=0x%x type=0x%x scancode=%d keycode=%d value=%d”,

rawEvent.deviceId, rawEvent.type, rawEvent.scanCode, rawEvent.keyCode,

rawEvent.value);

#endif

process(& rawEvent);

}

접기

4) InputReader.cpp – process – prcoess함수는 EventHub를 통해 받아온 이벤트를 처리한다. 처리되는 이벤트는 4종류로 분류된다. ( DEVICE_ADDED, DEVICE_REMOVED, FINISHED_DEVICE_SCAN, 기타)

접기

void InputReader::process(const RawEvent* rawEvent) {

switch (rawEvent->type) {

case EventHubInterface::DEVICE_ADDED:

addDevice(rawEvent->deviceId);

break;

case EventHubInterface::DEVICE_REMOVED:

removeDevice(rawEvent->deviceId);

break;

case EventHubInterface::FINISHED_DEVICE_SCAN:

handleConfigurationChanged(rawEvent->when);

break;

default:

consumeEvent(rawEvent);

break;

}

}

접기

① DEVICE_ADDED – addDevice()함수 – createDevice()를 호출하여 InputDevice 클래스를 생성하고 InputDevice의 configure() 함수를 호출함

접기

void InputReader::addDevice(int32_t deviceId) {

String8 name = mEventHub->getDeviceName(deviceId);

uint32_t classes = mEventHub->getDeviceClasses(deviceId);

InputDevice* device = createDevice(deviceId, name, classes);

device->configure();

if (device->isIgnored()) {

LOGI(“Device added: id=0x%x, name=%s (ignored non-input device)”, deviceId, name.string());

} else {

LOGI(“Device added: id=0x%x, name=%s, sources=%08x”, deviceId, name.string(),

device->getSources());

}

bool added = false;

{ // acquire device registry writer lock

RWLock::AutoWLock _wl(mDeviceRegistryLock);

ssize_t deviceIndex = mDevices.indexOfKey(deviceId);

if (deviceIndex < 0) {

mDevices.add(deviceId, device);

added = true;

}

} // release device registry writer lock

if (! added) {

LOGW(“Ignoring spurious device added event for deviceId %d.”, deviceId);

delete device;

return;

}

}

접기

② DEVICE_REMOVED – removeDevice() – 인자로 넘어온 deviceId를 가지고 deviceIndex를 구해서 해당 InputDevice 클래스를 삭제한다.

접기

void InputReader::removeDevice(int32_t deviceId) {

bool removed = false;

InputDevice* device = NULL;

{ // acquire device registry writer lock

RWLock::AutoWLock _wl(mDeviceRegistryLock);

ssize_t deviceIndex = mDevices.indexOfKey(deviceId);

if (deviceIndex >= 0) {

device = mDevices.valueAt(deviceIndex);

mDevices.removeItemsAt(deviceIndex, 1);

removed = true;

}

} // release device registry writer lock

if (! removed) {

LOGW(“Ignoring spurious device removed event for deviceId %d.”, deviceId);

return;

}

if (device->isIgnored()) {

LOGI(“Device removed: id=0x%x, name=%s (ignored non-input device)”,

device->getId(), device->getName().string());

} else {

LOGI(“Device removed: id=0x%x, name=%s, sources=%08x”,

device->getId(), device->getName().string(), device->getSources());

}

device->reset();

delete device;

}

접기

③ FINISHED_DEVICE_SCAN – handleConfigurationChanged() – InputDevice의 configuration을 업데이트한다.

접기

void InputReader::handleConfigurationChanged(nsecs_t when) {

// Reset global meta state because it depends on the list of all configured devices.

updateGlobalMetaState();

// Update input configuration.

updateInputConfiguration();

// Enqueue configuration changed.

mDispatcher->notifyConfigurationChanged(when);

}

접기

④ 나머지 – consumeEvent() – deviceId로 deviceIndex를 찾아서 InputDevice 클래스 정보를 가지고 온다. 그 다음 process() 함수를 호출한다.

접기

void InputReader::consumeEvent(const RawEvent* rawEvent) {

int32_t deviceId = rawEvent->deviceId;

{ // acquire device registry reader lock

RWLock::AutoRLock _rl(mDeviceRegistryLock);

ssize_t deviceIndex = mDevices.indexOfKey(deviceId);

if (deviceIndex < 0) {

LOGW(“Discarding event for unknown deviceId %d.”, deviceId);

return;

}

InputDevice* device = mDevices.valueAt(deviceIndex);

if (device->isIgnored()) {

//LOGD(“Discarding event for ignored deviceId %d.”, deviceId);

return;

}

device->process(rawEvent);

} // release device registry reader lock

}

접기

InputReader.cpp – InputDevice::process()

접기

void InputDevice::process(const RawEvent* rawEvent) {

size_t numMappers = mMappers.size();

for (size_t i = 0; i < numMappers; i++) {

InputMapper* mapper = mMappers[i];

mapper->process(rawEvent);

}

}

접기

InputReader.cpp – KeyboardInputMapper::process() – key 이벤트인 경우만 처리되고, processKey()함수를 호출한다.

접기

void KeyboardInputMapper::process(const RawEvent* rawEvent) {

switch (rawEvent->type) {

case EV_KEY: {

int32_t scanCode = rawEvent->scanCode;

if (isKeyboardOrGamepadKey(scanCode)) {

processKey(rawEvent->when, rawEvent->value != 0, rawEvent->keyCode, scanCode,

rawEvent->flags);

}

break;

}

}

}

접기

InputReader.cpp – KeyboardInputMapper::processKey() – key 이벤트를 처리하고  InputDispatcher의 notifyKey()함수를 호출한다.

접기

void KeyboardInputMapper::processKey(nsecs_t when, bool down, int32_t keyCode,

int32_t scanCode, uint32_t policyFlags) {

int32_t newMetaState;

nsecs_t downTime;

bool metaStateChanged = false;

{ // acquire lock

AutoMutex _l(mLock);

if (down) {

// Rotate key codes according to orientation if needed.

// Note: getDisplayInfo is non-reentrant so we can continue holding the lock.

if (mAssociatedDisplayId >= 0) {

int32_t orientation;

if (! getPolicy()->getDisplayInfo(mAssociatedDisplayId, NULL, NULL, & orientation)) {

return;

}

keyCode = rotateKeyCode(keyCode, orientation);

}

// Add key down.

ssize_t keyDownIndex = findKeyDownLocked(scanCode);

if (keyDownIndex >= 0) {

// key repeat, be sure to use same keycode as before in case of rotation

keyCode = mLocked.keyDowns.itemAt(keyDownIndex).keyCode;

} else {

// key down

mLocked.keyDowns.push();

KeyDown& keyDown = mLocked.keyDowns.editTop();

keyDown.keyCode = keyCode;

keyDown.scanCode = scanCode;

}

mLocked.downTime = when;

} else {

// Remove key down.

ssize_t keyDownIndex = findKeyDownLocked(scanCode);

if (keyDownIndex >= 0) {

// key up, be sure to use same keycode as before in case of rotation

keyCode = mLocked.keyDowns.itemAt(keyDownIndex).keyCode;

mLocked.keyDowns.removeAt(size_t(keyDownIndex));

} else {

// key was not actually down

LOGI(“Dropping key up from device %s because the key was not down.  ”

“keyCode=%d, scanCode=%d”,

getDeviceName().string(), keyCode, scanCode);

return;

}

}

int32_t oldMetaState = mLocked.metaState;

newMetaState = updateMetaState(keyCode, down, oldMetaState);

if (oldMetaState != newMetaState) {

mLocked.metaState = newMetaState;

metaStateChanged = true;

}

downTime = mLocked.downTime;

} // release lock

if (metaStateChanged) {

getContext()->updateGlobalMetaState();

}

getDispatcher()->notifyKey(when, getDeviceId(), AINPUT_SOURCE_KEYBOARD, policyFlags,

down ? AKEY_EVENT_ACTION_DOWN : AKEY_EVENT_ACTION_UP,

AKEY_EVENT_FLAG_FROM_SYSTEM, keyCode, scanCode, newMetaState, downTime);

}

접기

3.3.2 InputDispatcher 클래스 처리 순서

InputReader 클래스에서 처리된 이벤트 데이터를 저장하고 처리한다.

1) InputDispatcher.cpp – notifyKey() – 발생한 이벤트가 유효한지 validateKeyEvent()로 확인한 다음 – KeyEntry를 생성하고 – enqueueInboundEventLocked() 함수를 호출한다.

접기

void InputDispatcher::notifyKey(nsecs_t eventTime, int32_t deviceId, int32_t source,

uint32_t policyFlags, int32_t action, int32_t flags,

int32_t keyCode, int32_t scanCode, int32_t metaState, nsecs_t downTime) {

#if DEBUG_INBOUND_EVENT_DETAILS

LOGD(“notifyKey – eventTime=%lld, deviceId=0x%x, source=0x%x, policyFlags=0x%x, action=0x%x, ”

“flags=0x%x, keyCode=0x%x, scanCode=0x%x, metaState=0x%x, downTime=%lld”,

eventTime, deviceId, source, policyFlags, action, flags,

keyCode, scanCode, metaState, downTime);

#endif

if (! validateKeyEvent(action)) {

return;

}

policyFlags |= POLICY_FLAG_TRUSTED;

mPolicy->interceptKeyBeforeQueueing(eventTime, deviceId, action, /*byref*/ flags,

keyCode, scanCode, /*byref*/ policyFlags);

bool needWake;

{ // acquire lock

AutoMutex _l(mLock);

int32_t repeatCount = 0;

KeyEntry* newEntry = mAllocator.obtainKeyEntry(eventTime,

deviceId, source, policyFlags, action, flags, keyCode, scanCode,

metaState, repeatCount, downTime);

needWake = enqueueInboundEventLocked(newEntry);

} // release lock

if (needWake) {

mLooper->wake();

}

}

 

 

 

————————————–
Refer.:

https://source.android.com/devices/input/getevent.html

http://blog.csdn.net/learnrose/article/details/6236890

http://azard.me/blog/2015/06/13/android-cross-app-touch-event-injection/

http://muyu.tistory.com/entry/%EC%95%88%EB%93%9C%EB%A1%9C%EC%9D%B4%EB%93%9C%EC%9D%98-%EB%AA%A8%EB%93%A0-%EA%B2%83-%EB%B6%84%EC%84%9D%EA%B3%BC-%ED%8F%AC%ED%8C%85-4%EC%9E%A5-%EC%95%88%EB%93%9C%EB%A1%9C%EC%9D%B4%EB%93%9C-Input-Device-%EC%9A%94%EC%95%BD

 

 

 

Compiling C code (netcat) to native Android executable

If anybody else wants to know, this is from the NDK documentation:

SYSROOT=$NDK/platforms/android-<level>/arch-<arch>/
export CC="$NDK/toolchains/<name>/prebuilt/<system>/bin/<prefix>gcc --sysroot=$SYSROOT"
$CC -o foo.o -c foo.c

More specifically, for the netcat from https://github.com/android/platform_external_netcat

SYSROOT=$NDK/platforms/android-19/arch-arm
CC=$NDK/toolchains/arm-linux-androideabi-4.8/prebuilt/linux-x86_64/bin/arm-linux-androideabi-gcc --sysroot=$SYSROOT
$CC -DANDROID -c -o atomicio.o atomicio.c
$CC -DANDROID -c -o netcat.o netcat.c
$CC -o netcat atomicio.o netcat.o

Replace the paths from SYSROOT and CC as appropriate.

 

 

Ref.:

http://stackoverflow.com/questions/6168303/compiling-c-code-netcat-to-native-android-executable