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

Cross-compile source for Android

1. Use the ndk-build and an Android.mk

Prerequisites:

1. Linux Host (not yet tried on windows)

2. Android NDK on host machine

Let’s create a simple hello world C program in file test.c

#include <stdio.h>
#include <stdlib.h>
int main()
{
     printf("Hello World\n");
     return 0;
}

So, above program will just print “Hello World” on standard output.

Now, to compile it with NDK, we need a Android.mk. the Android.mk will look like this.

LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS) 
# give module name
LOCAL_MODULE    := hello_world  
# list your C files to compile
LOCAL_SRC_FILES := test.c
# this option will build executables instead of building library for android application.
include $(BUILD_EXECUTABLE)

The NDK system is only able to compile in android project hierarchy.

So, we need to create a directory structure like this

hello_world
     |
     `-- jni
     `-- libs

Now, place test.c and Android.mk file in jni directory.

Follow these steps on command line:

     $ mkdir  ~/hello_world/
     $ mkdir ~/hello_world/jni
     $ mkdir ~/hello_world/libs
     $ cd ~/hello_world/jni/
     $ gedit test.c
               # create your C code in file, save and exit.
     $ gedit Android.mk
               # write Android.mk contents, save and exit.
     $ export PATH=$PATH:<path/to/ndk>/
     $ ndk-build

By executing “ndk-build”, ndk will compile our test.c (not static) and puts the binary in hello_world/libs/armeabi/

 

So, take netcat for android as example:

https://github.com/android/platform_external_netcat

First, create a root directory

$ mkdir workDir

$ cd workDir

Then download the source

$ git clone https://github.com/android/platform_external_netcat.git

Create two directory – jni  and libs

$ mkdir jni

$ mkdir libs

move all sources to the jni folder

$ mv platform_external_netcat/* jni

Compile, then you will get the result at the libs folder

$ ndk-build

 

 

2. Use the tool-chain

although the first method is simple and straight, this time let’s try to compile it with traditional method.

I tried to write a makefile for that, but I gave up and wrote shell since I was not that good at writing makefile… T..T

compile.sh:

export NDK=/home/jiafei427/software/android-ndk-r11c
export SYSROOT=$NDK/platforms/android-23/arch-arm64
export CC=$NDK/toolchains/aarch64-linux-android-4.9/prebuilt/linux-x86_64/bin/aarch64-linux-android-gcc
echo”remove prebuilt files…”
rm -rf *.o
rm -rf netcat

echo “$CC –sysroot=$SYSROOT -DANDROID -c -o atomicio.o atomicio.c”
$CC –sysroot=$SYSROOT -DANDROID -fPIE -c -o atomicio.o atomicio.c
echo “$CC -DANDROID -c -o netcat.o netcat.c”
$CC –sysroot=$SYSROOT -DANDROID -fPIE -c -o netcat.o netcat.c
echo “$CC -o netcat atomicio.o netcat.o”
$CC –sysroot=$SYSROOT -fPIE -pie -o netcat atomicio.o netcat.o

Run this shell will compile the sources and create netcat program.

 

 

 

 

Refer.:

https://rathodpratik.wordpress.com/2013/03/24/build-cc-executables-for-android-using-ndk/

 

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

 

 

 

Compile USBSERIAL Module for target Kernel

Following source files must be donwloaded:

%ec%ba%a1%ec%b2%98

Makefile:

KERNEL_DIR=/home/jiafei427/workspace/tegra

CONFIG_MODULE_FORCE_UNLOAD=y

EXTRA_CFLAGS=-g -O0

obj-m += usbserial.o

usbserial-obj-y += console.o
#usbserial-obj-n += ezusb.o

usbserial-objs := usb-serial.o generic.o bus.o
PWD := $(shell pwd)
default:
$(MAKE) ARCH=arm64 CROSS_COMPILE=~/software/android-ndk-r11c/toolchains/aarch64-linux-android-4.9/prebuilt/linux-x86_64/bin/aarch64-linux-android- -C $(KERNEL_DIR) SUBDIRS=$(PWD) modules
#$(MAKE) ARCH=arm64 CROSS_COMPILE=~/software/android-ndk-r11c/toolchains/aarch64-linux-android-4.9/prebuilt/linux-x86_64/bin/aarch64-linux-android- -C $(KERNEL_DIR) SUBDIRS=$(PWD) modules
clean:
$(MAKE) -C $(KERNEL_DIR) SUBDIRS=$(PWD) clean

 

#make

That’s it, then you will be able to get the usbserial.ko file to install.

 

**IMPORTANT**

Make sure you made the KERNEL source compiled with MODULE INSTALL SUPPORTED

otherwise, you will get following error:

jiafei427@CKUBU:~/workspace/kernel/modules/usb-serial$ make
make ARCH=arm64 CROSS_COMPILE=~/software/android-ndk-r11c/toolchains/aarch64-linux-android-4.9/prebuilt/linux-x86_64/bin/aarch64-linux-android- -C /home/jiafei427/workspace/tegra SUBDIRS=/home/jiafei427/workspace/kernel/modules/usb-serial modules
make[1]: Entering directory ‘/home/jiafei427/workspace/tegra’
CC [M] /home/jiafei427/workspace/kernel/modules/usb-serial/usb-serial.o
CC [M] /home/jiafei427/workspace/kernel/modules/usb-serial/generic.o
CC [M] /home/jiafei427/workspace/kernel/modules/usb-serial/bus.o
LD [M] /home/jiafei427/workspace/kernel/modules/usb-serial/usbserial.o
Building modules, stage 2.
MODPOST 1 modules
WARNING: “tty_port_tty_get” [/home/jiafei427/workspace/kernel/modules/usb-serial/usbserial.ko] undefined!
WARNING: “system_wq” [/home/jiafei427/workspace/kernel/modules/usb-serial/usbserial.ko] undefined!
WARNING: “bus_register” [/home/jiafei427/workspace/kernel/modules/usb-serial/usbserial.ko] undefined!
WARNING: “device_remove_file” [/home/jiafei427/workspace/kernel/modules/usb-serial/usbserial.ko] undefined!
WARNING: “__kmalloc” [/home/jiafei427/workspace/kernel/modules/usb-serial/usbserial.ko] undefined!
WARNING: “test_and_clear_bit” [/home/jiafei427/workspace/kernel/modules/usb-serial/usbserial.ko] undefined!
WARNING: “driver_register” [/home/jiafei427/workspace/kernel/modules/usb-serial/usbserial.ko] undefined!
WARNING: “__kfifo_out” [/home/jiafei427/workspace/kernel/modules/usb-serial/usbserial.ko] undefined!
WARNING: “_raw_spin_unlock” [/home/jiafei427/workspace/kernel/modules/usb-serial/usbserial.ko] undefined!
WARNING: “single_open” [/home/jiafei427/workspace/kernel/modules/usb-serial/usbserial.ko] undefined!
WARNING: “__kfifo_alloc” [/home/jiafei427/workspace/kernel/modules/usb-serial/usbserial.ko] undefined!
WARNING: “handle_sysrq” [/home/jiafei427/workspace/kernel/modules/usb-serial/usbserial.ko] undefined!
WARNING: “single_release” [/home/jiafei427/workspace/kernel/modules/usb-serial/usbserial.ko] undefined!
WARNING: “seq_puts” [/home/jiafei427/workspace/kernel/modules/usb-serial/usbserial.ko] undefined!
WARNING: “tty_port_open” [/home/jiafei427/workspace/kernel/modules/usb-serial/usbserial.ko] undefined!
WARNING: “find_next_bit” [/home/jiafei427/workspace/kernel/modules/usb-serial/usbserial.ko] undefined!
WARNING: “seq_printf” [/home/jiafei427/workspace/kernel/modules/usb-serial/usbserial.ko] undefined!
WARNING: “tty_port_hangup” [/home/jiafei427/workspace/kernel/modules/usb-serial/usbserial.ko] undefined!
WARNING: “cancel_work_sync” [/home/jiafei427/workspace/kernel/modules/usb-serial/usbserial.ko] undefined!
WARNING: “usb_kill_urb” [/home/jiafei427/workspace/kernel/modules/usb-serial/usbserial.ko] undefined!
WARNING: “tty_register_driver” [/home/jiafei427/workspace/kernel/modules/usb-serial/usbserial.ko] undefined!
WARNING: “mutex_unlock” [/home/jiafei427/workspace/kernel/modules/usb-serial/usbserial.ko] undefined!
WARNING: “usb_autopm_get_interface” [/home/jiafei427/workspace/kernel/modules/usb-serial/usbserial.ko] undefined!
WARNING: “put_tty_driver” [/home/jiafei427/workspace/kernel/modules/usb-serial/usbserial.ko] undefined!
WARNING: “clear_bit” [/home/jiafei427/workspace/kernel/modules/usb-serial/usbserial.ko] undefined!
WARNING: “sprintf” [/home/jiafei427/workspace/kernel/modules/usb-serial/usbserial.ko] undefined!
WARNING: “seq_read” [/home/jiafei427/workspace/kernel/modules/usb-serial/usbserial.ko] undefined!
WARNING: “jiffies” [/home/jiafei427/workspace/kernel/modules/usb-serial/usbserial.ko] undefined!
WARNING: “tty_set_operations” [/home/jiafei427/workspace/kernel/modules/usb-serial/usbserial.ko] undefined!
WARNING: “__kfifo_max_r” [/home/jiafei427/workspace/kernel/modules/usb-serial/usbserial.ko] undefined!
WARNING: “test_and_set_bit” [/home/jiafei427/workspace/kernel/modules/usb-serial/usbserial.ko] undefined!
WARNING: “tty_port_close” [/home/jiafei427/workspace/kernel/modules/usb-serial/usbserial.ko] undefined!
WARNING: “device_del” [/home/jiafei427/workspace/kernel/modules/usb-serial/usbserial.ko] undefined!
WARNING: “dev_err” [/home/jiafei427/workspace/kernel/modules/usb-serial/usbserial.ko] undefined!
WARNING: “_raw_spin_unlock_irqrestore” [/home/jiafei427/workspace/kernel/modules/usb-serial/usbserial.ko] undefined!
WARNING: “usb_deregister” [/home/jiafei427/workspace/kernel/modules/usb-serial/usbserial.ko] undefined!
WARNING: “__mutex_init” [/home/jiafei427/workspace/kernel/modules/usb-serial/usbserial.ko] undefined!
WARNING: “printk” [/home/jiafei427/workspace/kernel/modules/usb-serial/usbserial.ko] undefined!
WARNING: “tty_ldisc_deref” [/home/jiafei427/workspace/kernel/modules/usb-serial/usbserial.ko] undefined!
WARNING: “driver_unregister” [/home/jiafei427/workspace/kernel/modules/usb-serial/usbserial.ko] undefined!
WARNING: “usb_unpoison_urb” [/home/jiafei427/workspace/kernel/modules/usb-serial/usbserial.ko] undefined!
WARNING: “usb_poison_urb” [/home/jiafei427/workspace/kernel/modules/usb-serial/usbserial.ko] undefined!
WARNING: “seq_putc” [/home/jiafei427/workspace/kernel/modules/usb-serial/usbserial.ko] undefined!
WARNING: “_raw_spin_unlock_irq” [/home/jiafei427/workspace/kernel/modules/usb-serial/usbserial.ko] undefined!
WARNING: “tty_port_init” [/home/jiafei427/workspace/kernel/modules/usb-serial/usbserial.ko] undefined!
WARNING: “tty_insert_flip_string_fixed_flag” [/home/jiafei427/workspace/kernel/modules/usb-serial/usbserial.ko] undefined!
WARNING: “warn_slowpath_null” [/home/jiafei427/workspace/kernel/modules/usb-serial/usbserial.ko] undefined!
WARNING: “tty_port_destroy” [/home/jiafei427/workspace/kernel/modules/usb-serial/usbserial.ko] undefined!
WARNING: “tty_vhangup” [/home/jiafei427/workspace/kernel/modules/usb-serial/usbserial.ko] undefined!
WARNING: “tty_ldisc_ref” [/home/jiafei427/workspace/kernel/modules/usb-serial/usbserial.ko] undefined!
WARNING: “idr_alloc” [/home/jiafei427/workspace/kernel/modules/usb-serial/usbserial.ko] undefined!
WARNING: “device_add” [/home/jiafei427/workspace/kernel/modules/usb-serial/usbserial.ko] undefined!
WARNING: “bus_unregister” [/home/jiafei427/workspace/kernel/modules/usb-serial/usbserial.ko] undefined!
WARNING: “usb_store_new_id” [/home/jiafei427/workspace/kernel/modules/usb-serial/usbserial.ko] undefined!
WARNING: “tty_insert_flip_string_flags” [/home/jiafei427/workspace/kernel/modules/usb-serial/usbserial.ko] undefined!
WARNING: “usb_match_id” [/home/jiafei427/workspace/kernel/modules/usb-serial/usbserial.ko] undefined!
WARNING: “tty_register_device” [/home/jiafei427/workspace/kernel/modules/usb-serial/usbserial.ko] undefined!
WARNING: “idr_remove” [/home/jiafei427/workspace/kernel/modules/usb-serial/usbserial.ko] undefined!
WARNING: “device_create_file” [/home/jiafei427/workspace/kernel/modules/usb-serial/usbserial.ko] undefined!
WARNING: “tty_port_tty_wakeup” [/home/jiafei427/workspace/kernel/modules/usb-serial/usbserial.ko] undefined!
WARNING: “tty_unregister_device” [/home/jiafei427/workspace/kernel/modules/usb-serial/usbserial.ko] undefined!
WARNING: “_dev_info” [/home/jiafei427/workspace/kernel/modules/usb-serial/usbserial.ko] undefined!
WARNING: “usb_submit_urb” [/home/jiafei427/workspace/kernel/modules/usb-serial/usbserial.ko] undefined!
WARNING: “tty_std_termios” [/home/jiafei427/workspace/kernel/modules/usb-serial/usbserial.ko] undefined!
WARNING: “idr_find_slowpath” [/home/jiafei427/workspace/kernel/modules/usb-serial/usbserial.ko] undefined!
WARNING: “usb_get_dev” [/home/jiafei427/workspace/kernel/modules/usb-serial/usbserial.ko] undefined!
WARNING: “put_device” [/home/jiafei427/workspace/kernel/modules/usb-serial/usbserial.ko] undefined!
WARNING: “usb_put_dev” [/home/jiafei427/workspace/kernel/modules/usb-serial/usbserial.ko] undefined!
WARNING: “schedule” [/home/jiafei427/workspace/kernel/modules/usb-serial/usbserial.ko] undefined!
WARNING: “_raw_spin_lock_irq” [/home/jiafei427/workspace/kernel/modules/usb-serial/usbserial.ko] undefined!
WARNING: “__raw_spin_lock_init” [/home/jiafei427/workspace/kernel/modules/usb-serial/usbserial.ko] undefined!
WARNING: “__kfifo_in_r” [/home/jiafei427/workspace/kernel/modules/usb-serial/usbserial.ko] undefined!
WARNING: “tty_port_install” [/home/jiafei427/workspace/kernel/modules/usb-serial/usbserial.ko] undefined!
WARNING: “_raw_spin_lock” [/home/jiafei427/workspace/kernel/modules/usb-serial/usbserial.ko] undefined!
WARNING: “usb_get_intf” [/home/jiafei427/workspace/kernel/modules/usb-serial/usbserial.ko] undefined!
WARNING: “_raw_spin_lock_irqsave” [/home/jiafei427/workspace/kernel/modules/usb-serial/usbserial.ko] undefined!
WARNING: “tty_termios_copy_hw” [/home/jiafei427/workspace/kernel/modules/usb-serial/usbserial.ko] undefined!
WARNING: “__kfifo_free” [/home/jiafei427/workspace/kernel/modules/usb-serial/usbserial.ko] undefined!
WARNING: “tty_unregister_driver” [/home/jiafei427/workspace/kernel/modules/usb-serial/usbserial.ko] undefined!
WARNING: “tty_hangup” [/home/jiafei427/workspace/kernel/modules/usb-serial/usbserial.ko] undefined!
WARNING: “usb_show_dynids” [/home/jiafei427/workspace/kernel/modules/usb-serial/usbserial.ko] undefined!
WARNING: “__wake_up” [/home/jiafei427/workspace/kernel/modules/usb-serial/usbserial.ko] undefined!
WARNING: “prepare_to_wait_event” [/home/jiafei427/workspace/kernel/modules/usb-serial/usbserial.ko] undefined!
WARNING: “__tty_alloc_driver” [/home/jiafei427/workspace/kernel/modules/usb-serial/usbserial.ko] undefined!
WARNING: “mutex_lock_nested” [/home/jiafei427/workspace/kernel/modules/usb-serial/usbserial.ko] undefined!
WARNING: “usb_disabled” [/home/jiafei427/workspace/kernel/modules/usb-serial/usbserial.ko] undefined!
WARNING: “warn_slowpath_fmt” [/home/jiafei427/workspace/kernel/modules/usb-serial/usbserial.ko] undefined!
WARNING: “tty_termios_baud_rate” [/home/jiafei427/workspace/kernel/modules/usb-serial/usbserial.ko] undefined!
WARNING: “seq_lseek” [/home/jiafei427/workspace/kernel/modules/usb-serial/usbserial.ko] undefined!
WARNING: “schedule_timeout_interruptible” [/home/jiafei427/workspace/kernel/modules/usb-serial/usbserial.ko] undefined!
WARNING: “kfree” [/home/jiafei427/workspace/kernel/modules/usb-serial/usbserial.ko] undefined!
WARNING: “set_bit” [/home/jiafei427/workspace/kernel/modules/usb-serial/usbserial.ko] undefined!
WARNING: “device_initialize” [/home/jiafei427/workspace/kernel/modules/usb-serial/usbserial.ko] undefined!
WARNING: “usb_match_one_id” [/home/jiafei427/workspace/kernel/modules/usb-serial/usbserial.ko] undefined!
WARNING: “usb_register_driver” [/home/jiafei427/workspace/kernel/modules/usb-serial/usbserial.ko] undefined!
WARNING: “lockdep_init_map” [/home/jiafei427/workspace/kernel/modules/usb-serial/usbserial.ko] undefined!
WARNING: “tty_kref_put” [/home/jiafei427/workspace/kernel/modules/usb-serial/usbserial.ko] undefined!
WARNING: “finish_wait” [/home/jiafei427/workspace/kernel/modules/usb-serial/usbserial.ko] undefined!
WARNING: “dev_warn” [/home/jiafei427/workspace/kernel/modules/usb-serial/usbserial.ko] undefined!
WARNING: “driver_attach” [/home/jiafei427/workspace/kernel/modules/usb-serial/usbserial.ko] undefined!
WARNING: “tty_flip_buffer_push” [/home/jiafei427/workspace/kernel/modules/usb-serial/usbserial.ko] undefined!
WARNING: “__kfifo_in” [/home/jiafei427/workspace/kernel/modules/usb-serial/usbserial.ko] undefined!
WARNING: “queue_work_on” [/home/jiafei427/workspace/kernel/modules/usb-serial/usbserial.ko] undefined!
WARNING: “snprintf” [/home/jiafei427/workspace/kernel/modules/usb-serial/usbserial.ko] undefined!
WARNING: “param_ops_ushort” [/home/jiafei427/workspace/kernel/modules/usb-serial/usbserial.ko] undefined!
WARNING: “dev_set_name” [/home/jiafei427/workspace/kernel/modules/usb-serial/usbserial.ko] undefined!
WARNING: “usb_free_urb” [/home/jiafei427/workspace/kernel/modules/usb-serial/usbserial.ko] undefined!
WARNING: “usb_autopm_put_interface” [/home/jiafei427/workspace/kernel/modules/usb-serial/usbserial.ko] undefined!
WARNING: “__kfifo_out_r” [/home/jiafei427/workspace/kernel/modules/usb-serial/usbserial.ko] undefined!
WARNING: “usb_alloc_urb” [/home/jiafei427/workspace/kernel/modules/usb-serial/usbserial.ko] undefined!
WARNING: “usb_put_intf” [/home/jiafei427/workspace/kernel/modules/usb-serial/usbserial.ko] undefined!
CC /home/jiafei427/workspace/kernel/modules/usb-serial/usbserial.mod.o
/home/jiafei427/workspace/kernel/modules/usb-serial/usbserial.mod.c:8:1: error: variable ‘__this_module’ has initializer but incomplete type
__attribute__((section(“.gnu.linkonce.this_module”))) = {
^
/home/jiafei427/workspace/kernel/modules/usb-serial/usbserial.mod.c:9:2: error: unknown field ‘name’ specified in initializer
.name = KBUILD_MODNAME,
^
/home/jiafei427/workspace/kernel/modules/usb-serial/usbserial.mod.c:9:2: warning: excess elements in struct initializer
/home/jiafei427/workspace/kernel/modules/usb-serial/usbserial.mod.c:9:2: warning: (near initialization for ‘__this_module’)
/home/jiafei427/workspace/kernel/modules/usb-serial/usbserial.mod.c:10:2: error: unknown field ‘init’ specified in initializer
.init = init_module,
^
/home/jiafei427/workspace/kernel/modules/usb-serial/usbserial.mod.c:10:2: warning: excess elements in struct initializer
/home/jiafei427/workspace/kernel/modules/usb-serial/usbserial.mod.c:10:2: warning: (near initialization for ‘__this_module’)
/home/jiafei427/workspace/kernel/modules/usb-serial/usbserial.mod.c:14:2: error: unknown field ‘arch’ specified in initializer
.arch = MODULE_ARCH_INIT,
^
/home/jiafei427/workspace/kernel/modules/usb-serial/usbserial.mod.c:14:10: error: ‘MODULE_ARCH_INIT’ undeclared here (not in a function)
.arch = MODULE_ARCH_INIT,
^
/home/jiafei427/workspace/kernel/modules/usb-serial/usbserial.mod.c:14:2: warning: excess elements in struct initializer
.arch = MODULE_ARCH_INIT,
^
/home/jiafei427/workspace/kernel/modules/usb-serial/usbserial.mod.c:14:2: warning: (near initialization for ‘__this_module’)
scripts/Makefile.modpost:114: recipe for target ‘/home/jiafei427/workspace/kernel/modules/usb-serial/usbserial.mod.o’ failed
make[2]: *** [/home/jiafei427/workspace/kernel/modules/usb-serial/usbserial.mod.o] Error 1
Makefile:1401: recipe for target ‘modules’ failed
make[1]: *** [modules] Error 2
make[1]: Leaving directory ‘/home/jiafei427/workspace/tegra’
Makefile:17: recipe for target ‘default’ failed
make: *** [default] Error 2

#### make failed to build some targets (1 seconds) ####

 

Appendix: (Kernel Configuration Option Info.)

kernel_module

 


 

Earlier we discussed how to compile a kernel from the source.

This tutorial explains how to write a Kernel module using a simple Hello World example.

I. Utilities to Manipulate Kernel Modules

1. lsmod – List Modules that Loaded Already

lsmod command will list modules that are already loaded in the kernel as shown beblow.

# lsmod
Module                  Size  Used by
ppp_deflate            12806  0 
zlib_deflate           26445  1 ppp_deflate
bsd_comp               12785  0 
..

2. insmod – Insert Module into Kernel

insmod command will insert a new module into the kernel as shown below.

# insmod /lib/modules/3.5.0-19-generic/kernel/fs/squashfs/squashfs.ko

# lsmod | grep "squash"
squashfs               35834  0

3. modinfo – Display Module Info

modinfo command will display information about a kernel module as shown below.

# modinfo /lib/modules/3.5.0-19-generic/kernel/fs/squashfs/squashfs.ko

filename:       /lib/modules/3.5.0-19-generic/kernel/fs/squashfs/squashfs.ko
license:        GPL
author:         Phillip Lougher 
description:    squashfs 4.0, a compressed read-only filesystem
srcversion:     89B46A0667BD5F2494C4C72
depends:        
intree:         Y
vermagic:       3.5.0-19-generic SMP mod_unload modversions 686

4. rmmod – Remove Module from Kernel

rmmod command will remove a module from the kernel. You cannot remove a module which is already used by any program.

# rmmod squashfs.ko

5. modprobe – Add or Remove modules from the kernel

modprobe is an intelligent command which will load/unload modules based on the dependency between modules. Refer to modprobe commands for more detailed examples.

II. Write a Simple Hello World Kernel Module

1. Installing the linux headers

You need to install the linux-headers-.. first as shown below. Depending on your distro, use apt-get or yum.

# apt-get install build-essential linux-headers-$(uname -r)

2. Hello World Module Source Code

Next, create the following hello.c module in C programming language.

#include <linux/module.h>    // included for all kernel modules
#include <linux/kernel.h>    // included for KERN_INFO
#include <linux/init.h>      // included for __init and __exit macros

MODULE_LICENSE("GPL");
MODULE_AUTHOR("Lakshmanan");
MODULE_DESCRIPTION("A Simple Hello World module");

static int __init hello_init(void)
{
    printk(KERN_INFO "Hello world!\n");
    return 0;    // Non-zero return means that the module couldn't be loaded.
}

static void __exit hello_cleanup(void)
{
    printk(KERN_INFO "Cleaning up module.\n");
}

module_init(hello_init);
module_exit(hello_cleanup);

Warning: All kernel modules will operate on kernel space, a highly privileged mode. So be careful with what you write in a kernel module.

3. Create Makefile to Compile Kernel Module

The following makefile can be used to compile the above basic hello world kernel module.

obj-m += hello.o

all:
    make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules

clean:
    make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean

Use the make command to compile hello world kernel module as shown below.

# make

make -C /lib/modules/3.5.0-19-generic/build M=/home/lakshmanan/a modules
make[1]: Entering directory `/usr/src/linux-headers-3.5.0-19-generic'
  CC [M]  /home/lakshmanan/a/hello.o
  Building modules, stage 2.
  MODPOST 1 modules
  CC      /home/lakshmanan/a/hello.mod.o
  LD [M]  /home/lakshmanan/a/hello.ko
make[1]: Leaving directory `/usr/src/linux-headers-3.5.0-19-generic'

The above will create hello.ko file, which is our sample Kernel module.

4. Insert or Remove the Sample Kernel Module

Now that we have our hello.ko file, we can insert this module to the kernel by using insmod command as shown below.

# insmod hello.ko

# dmesg | tail -1
[ 8394.731865] Hello world!

# rmmod hello.ko

# dmesg | tail -1
[ 8707.989819] Cleaning up module.

When a module is inserted into the kernel, the module_init macro will be invoked, which will call the function hello_init. Similarly, when the module is removed with rmmod, module_exit macro will be invoked, which will call the hello_exit. Using dmesg command, we can see the output from the sample Kernel module.


 

Refer.

 

How to Write Your Own Linux Kernel Module with a Simple Example

 

Python Crawling Start

Basic Source:


# -*- coding: utf8 -*-
import locale, os
import sys
reload(sys)
sys.setdefaultencoding(‘utf-8’)

import requests
from bs4 import BeautifulSoup

def spider(max_pages):
showMsg()
hoo = unicode(‘한글’, ‘utf-8’)
print str(hoo.encode(‘utf-8’))
# 유니코드로 다루기 예제1
hoo = unicode(‘한글’, ‘utf-8’)
print str(hoo.encode(‘utf-8’))

# 유니코드로 다루기 예제2
bar = ‘한글’.decode(‘utf-8’)
print bar.encode(‘utf-8′)

# 유니코드로 다루기 예제3
foo = u’한글’
print str(foo.encode(‘utf-8’))
page = 1
while page < max_pages:
url = ‘http://www.clien.net/cs2/bbs/board.php?bo_table=jirum&page=&#8217; + str(page)
source_code = requests.get(url)
plain_text = source_code.content
soup = BeautifulSoup(plain_text, ‘html.parser’, from_encoding=”utf-8″)
for link in soup.find_all(“td”, class_=”post_subject”):
href = “http://www.clien.net/cs2&#8221; + link.a.get(‘href’)[2:]
title = link.a.string
print(href)
print(title)
page += 1

spider(2)


 

요즘엔 requests라는 라이브러리를 많이 사용하고 실제로 써보니 확실히 많이 편하구요.

처음 requests를 사용한건 IP 조회 코드가 필요해서 쓰게 됬는데, 그 이후로 웹 관련 코드 작성할 때는 requests만 쓰고 있습니다.

다만 이 라이브러리에서의 문제는 간혹 한글이 깨져서 출력되는 경우가 있다는 것…

웹 페이지 인코딩 설정에 따라 다른 것 같은데 req.text로 결과값을 가져올 경우 한글이 깨지는 경우가 발생합니다.
http://pwnbit.kr/plugin/CallBack_bootstrapperSrc?nil_profile=tistory&nil_type=copied_post

문제 해결은 간단하게 해결했는데.. req.content로 결과값을 출력시켜주면 됩니다.

원인은 req.text는 값을 ‘unicode’형으로 가져옵니다.

반면, req.content는 ‘str’형으로 값을 가져오구요.

unicode로 값을 가져올 경우 코딩하다보면 아주 짜증나는 문자 체계덕에 좀 꼬이는 경우가 발생하는 것 같습니다.

unicode 처리할 때 종종 쓰는 codecs 라이브러리나 다른 .encode(), unicode() 등을 쓰지 않고도 requests 라이브러리 자체적으로 해결되니 진짜 잘 만들어진 라이브러리란 생각도 드네요.

 

 

Ref.:

http://pwnbit.kr/85