Complete process analysis from the android upper-layer interface to the kernel code, using alarm as an Example

Source: Internet
Author: User

A process document that was written a long time ago, from the upper interface to the kernel calling process. Recently, my colleagues asked me to read it and I am sorting it out again, this is purely personal analysis (but all operations have been verified). If not, please point it out.

The alarm calling process implements the calling process from the upper-layer application to the driver below. The following is a brief description:

Code involved;
./Packages/apps/deskclock/src/COM/Android/deskclock/alarms. Java
./Frameworks/base/CORE/Java/Android/APP/alarmmanager. Java
./Frameworks/base/services/Java/COM/Android/Server/alarmmanagerservice. Java
./Frameworks/base/services/JNI/com_android_server_alarmmanagerservice.cpp
./Kernel/Drivers/RTC/alarm-dev.c
./Kernel/include/Linux/android_alarm.h
./Kernel/Drivers/RTC/alarm. c
./Kernel/Drivers/RTC/interface. c
./Kernel/Drivers/RTC/rtc-pcf8563.c

./Packages/apps/deskclock/src/COM/Android/deskclock/alarmreceiver. Java

./Kernel/ARCH/ARM/configs/matrix _ android_defconfig
./Kernel/. config

Click the clock application, and set a new alarm, which will be adjusted to
Public static long setalarm (context, alarm ){
....
Setnextalert (context );
....
}
Then it will call
Public static void setnextalert (final context ){
If (! Enablesnoozealert (context )){
Alarm alarm = calculatenextalert (context); // a new alarm
If (alarm! = NULL ){
Enablealert (context, alarm, alarm. time );
} Else {
Disablealert (context );
}
}
}
Then continue to call
Private Static void enablealert (context, final alarm, final long attimeinmillis ){
.......
Am. set (alarmmanager. rtc_wakeup, attimeinmillis, Sender); // This is rtc_wakeup, which ensures that the system can wake up even if the system is asleep and the alarm clock works (the Android platform does not seem to be able to shut down the alarm)
.....
}

Then the method in alarmmanager. Java is called.
Public void set (INT type, long triggerattime, pendingintent operation ){
Try {
Mservice. Set (type, triggerattime, operation );
} Catch (RemoteException ex ){
}
}

Then the method in alarmmanagerservice. Java is called.
Public void set (INT type, long triggerattime, pendingintent operation ){
Setrepeating (type, triggerattime, 0, operation );
}

Then continue to call
Public void setrepeating (INT type, long triggerattime, long interval,
Pendingintent operation ){
.....
Synchronized (mlock ){
Alarm alarm = new alarm ();
Alarm. type = type;
Alarm. When = triggerattime;
Alarm. repeatinterval = interval;
Alarm. Operation = operation;

// Remove this alarm if already scheduled.
Removelocked (operation );

If (locallogv) slog. V (TAG, "set:" + alarm );

Int Index = addalarmlocked (Alarm );
If (Index = 0 ){
Setlocked (Alarm );
}
}
}

Then
Private void setlocked (ALARM alarm)
{
......
Set (mdescriptor, alarm. type, alarmseconds, alarmnanoseconds); // mdescriptor file:/dev/alarm
.....
}

JNI is called here.
Private native void set (int fd, int type, long seconds, long nanoseconds );

This is called in com_android_server_alarmmanagerservice.cpp.
Static jninativemethod smethods [] = {
/* Name, signature, funcptr */
{"Init", "() I", (void *) android_server_alarmmanagerservice_init },
{"Close", "(I) V", (void *) android_server_alarmmanagerservice_close },
{"Set", "(iijj) V", (void *) android_server_alarmmanagerservice_set },
{"Waitforalarm", "(I) I", (void *) android_server_alarmmanagerservice_waitforalarm },
{"Setkerneltimezone", "(ii) I", (void *) android_server_alarmmanagerservice_setkerneltimezone },
};

Set corresponds to android_server_alarmmanagerservice_set, which is
Static void android_server_alarmmanagerservice_set (jnienv * ENV, jobject OBJ, jint FD, jint type, jlong seconds, jlong nanoseconds)
{
# If have_android_ OS
Struct timespec ts;
TS. TV _sec = seconds;
TS. TV _nsec = nanoseconds;

Int result = IOCTL (FD, android_alarm_set (type), & TS );
If (result <0)
{
LogE ("unable to set alarm to % LLD. % 09lld: % s \ n", seconds, nanoseconds, strerror (errno ));
}
# Endif
}

Then IOCTL calls the alarm-dev.c.
Static long alarm_ioctl (struct file * file, unsigned int cmd, unsigned long Arg)
{
....
Case android_alarm_set (0 ):
If (copy_from_user (& new_alarm_time, (void _ User *) Arg,
Sizeof (new_alarm_time ))){
Rv =-efault;
Goto err1;
}
From_old_alarm_set:
Spin_lock_irqsave (& alarm_slock, flags );
Pr_alarm (Io, "alarm % d Set % lD. % 09ld \ n", alarm_type,
New_alarm_time. TV _sec, new_alarm_time. TV _nsec );
Alarm_enabled | = alarm_type_mask;
Alarm_start_range (& alarms [alarm_type],
Timespec_to_ktime (new_alarm_time ),
Timespec_to_ktime (new_alarm_time ));
Spin_unlock_irqrestore (& alarm_slock, flags );
If (android_alarm_base_cmd (CMD )! = Android_alarm_set_and_wait (0)
& Cmd! = Android_alarm_set_and_wait_old)
Break;
/* Fall though */
....

Case android_alarm_set_rtc:
If (copy_from_user (& new_rtc_time, (void _ User *) Arg,
Sizeof (new_rtc_time ))){
Rv =-efault;
Goto err1;
}
Rv = alarm_set_rtc (new_rtc_time );
Spin_lock_irqsave (& alarm_slock, flags );
Alarm_pending | = android_alarm_time_change_mask;
Wake_up (& alarm_wait_queue );
Spin_unlock_irqrestore (& alarm_slock, flags );
If (RV <0)
Goto err1;
Break;
....
}

Then, alarm_start_range is called to set the alarm and alarm_set_rtc to set RTC.
These two functions are declared in android_alarm.h and implemented in alarm. C.
This is the statement in android_alarm.h.
Void alarm_start_range (struct alarm * Alarm, ktime_t start, ktime_t end );
Int alarm_try_to_cancel (struct alarm * Alarm );
Int alarm_cancel (struct alarm * Alarm );
Ktime_t alarm_get_elapsed_realtime (void );

/* Set RTC while preserving elapsed realtime */
Int alarm_set_rtc (const struct timespec TS );

The implementation in alarm. C is as follows:
Int alarm_set_rtc (struct timespec new_time)
{
....
Ret = rtc_set_time (alarm_rtc_dev, & rtc_new_rtc_time );
....
}

The alarm_suspend alarm_resume function is implemented in alarm. C.
If the system does not have suspend, setting an alarm will not write data to the Register of the RTC chip, because the system does not need to be awakened, so the time of the alarm data is written to the device file/dev/alarm through the upper layer.
It is okay, alarmthread will constantly go round to find the next time there is no alarm, directly read from the device file/dev/alarm
Second, if the system enters susupend, alarm's alarm_suspend will be written to the lower-layer RTC chip register. Then, even after the system's suspend, the alarm clock can wake up the system through RTC.

This is called in interface. C. // The Int rtc_set_alarm (struct rtc_device * RTC, struct rtc_wkalrm * Alarm) is similar to the following.
Int rtc_set_time (struct rtc_device * RTC, struct rtc_time * TM)
{
....
Err = RTC-> OPS-> set_time (RTC-> Dev. Parent, Tm );
....
}

Then set_time will see the specific RTC chip, here we are rtc-pcf8563.c
Static const struct rtc_class_ops pcf8563_rtc_ops = {
. Read_time = pcf8563_rtc_read_time,
. Set_time = pcf8563_rtc_set_time,
. Read_alarm = pcf8563_rtc_read_alarm,
. Set_alarm = pcf8563_rtc_set_alarm,
};
And then we get there.
Static int pcf8563_rtc_set_time (struct device * Dev, struct rtc_time * TM)
{
Unsigned char Buf [time_num];
Int ret;

Ret = data_calc (BUF, TM, time_num );
If (Ret <0)
Goto out;
Ret = i2c_smbus_write_i2c_block_data (pcf8563_info-> client, pcf8563_rtc_sec, time_num, Buf); // call the I2C unified interface to write data to the pcf8563rtc chip register.
Out:
Return ret;
}

At this point, the alarm clock time has been written into the registers of the RTC chip. The second parameter is the register name, The Buf is the time to write, and the RTC chip is powered by extra power, therefore, after the suspend of the system, the system kernel is shut down, but there is electricity in the RTC, and data in the register is still there (data will be lost when the power is down), so the alarm is triggered, the system can be awakened through the hardware interruption mechanism.

The above RTC has dozens of RTC chip driver codes, which have no similar structure. They all have basic operation functions and registration functions, all of which are unique register operations on their respective chips, why is pcf8563rtc called? This depends on the chip used by your system. You can view it through./kernel/. config. The pcf8563rtc here is the chip model currently in use by the system.
# Config_rtc_drv_isl1208 is not set
# Config_rtc_drv_x1205 is not set
Config_rtc_drv_pcf8563 = y
# Config_rtc_drv_pcf8583 is not set
# Config_rtc_drv_m41t80 is not set

The following describes how the alarm clock works after the system is awakened.
If the system does not have suspend, directly follow the following process. If suspend is awakened by RTC, the following process is followed.

Private class alarmthread extends thread
{
Public alarmthread ()
{
Super ("alarmmanager ");
}

Public void run ()
{
While (true)
{
Int result = waitforalarm (mdescriptor); // call JNI here to call static jint android_server_alarmmanagerservice_waitforalarm, mainly for/dev/alarm operations
....
Alarm alarm = it. Next ();
Try {
If (locallogv) slog. V (TAG, "sending alarm" + alarm );
Alarm. Operation. Send (mcontext, 0,
Mbackgroundintent. putextra (
Intent. extra_alarm_count, alarm. Count ),
Mresultreceiver, mhandler );
....
}

}
}

Static jint android_server_alarmmanagerservice_waitforalarm (jnienv * ENV, jobject OBJ, jint FD)
{
# If have_android_ OS
Int result = 0;

Do
{
Result = IOCTL (FD, android_alarm_wait );
} While (result <0 & errno = eintr );

If (result <0)
{
LogE ("unable to wait on alarm: % s \ n", strerror (errno ));
Return 0;
}

Return result;
# Endif
}

There is an alarmthread in alarmmanagerservice that will always poll the/dev/alarm file. If it fails to be opened, it will return directly. If it succeeds, it will perform some actions, such as searching for the latest time
Alarm, for example, when a sleep is awakened by an alarm, an intent will be sent out here, and then it will be received in the alarmreceiver. Java pop-up and the following will be called
Context. startactivity (alarmalert );

Then the alarm interface is displayed.
Class C = alarmalert. Class;
Among them, public class alarmalert extends alarmalertfullscreen is triggered by alarm after the system goes to sleep.
Public class alarmreceiver extends broadcastreceiver {

/** If the alarm is older than stale_window, ignore. it
Is probably the result of a time or timezone change */
Private Final Static int stale_window = 30x60*1000;

@ Override
Public void onreceive (context, intent ){
.........
Intent alarmalert = new intent (context, C );
Alarmalert. putextra (alarms. alarm_intent_extra, alarm );
Alarmalert. setflags (intent. flag_activity_new_task
| Intent. flag_activity_no_user_action );
Context. startactivity (alarmalert );
........
}

Now alarm is displayed.

I personally added the log to verify the process. When suspend and not suspend, alarm is the same as above.

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.