第十一章 Android 内核驱动——Alarm
11.1 基本原理
Alarm 闹钟是 android 系统中在标准 RTC 驱动上开发的一个新的驱动,提供了一个定时器 用于把设备从睡眠状态唤醒,当然因为它是依赖 RTC 驱动的,所以它同时还可以为系统提 供一个掉电下还能运行的实时时钟。
当系统断电时,主板上的 rtc 芯片将继续维持系统的时间,这样保证再次开机后系统的时间 不会错误。当系统开始时,内核从 RTC 中读取时间来初始化系统时间,关机时便又将系统 时间写回到 rtc 中,关机阶段将有主板上另外的电池来供应 rtc 计时。Android 中的 Alarm 在设备处于睡眠模式时仍保持活跃,它可以设置来唤醒设备。
上图为android系统中 alarm 和 rtc 驱动的框架。Alarm依赖于rtc 驱动框架,但它不是一个 rtc 驱动,主要还是实现定时闹钟的功能。相关源代码在 kernel/drivers/rtc/alarm.c 和 drivers/rtc/alarm_dev.c。
其中 alarm.c 文件实现的是所有 alarm 设备的通用性操作,它创建了一个设备 class,而
www.linuxidc.com
Linux公社(LinuxIDC.com) 是包括Ubuntu,Fedora,SUSE技术,最新IT资讯等Linux专业类网站。
alarm_dev.c 则创建具体的 alarm 设备,注册到该设备 class 中。 alarm.c 还实现了与 interface.c 的接口,即建立了与具体 rtc 驱动和rtc 芯片的联系。 alarm_dev.c在 alarm.c 基础包装了一层, 主要是实现了标准的 miscdevice 接口,提供给应用层调用。
可以这样概括:alarm.c 实现的是机制和框架,alarm_dev.c 则是实现符合这个框架的设备驱 动,alarm_dev.c 相当于在底层硬件 rtc 闹钟功能的基础上虚拟了多个软件闹钟。
11.2 关键数据结构
alarm 定义在 include/linux/android_alarm.h 中。 struct alarm { struct rb_node node; enum android_alarm_type type; ktime_t softexpires; //最早的到期时间 ktime_t expires; //绝对到期时间 void (*function)(struct alarm *); //当到期时系统回调该函数 };
这个结构体代表 alarm 设备,所有的 alarm 设备按照它们过期时间的先后被组织成一 个红黑树,alarm.node 即红黑树的节点,alarm 设备通过这个变量插入红黑树。 alarm.type 是类型,android 中一共定义了如下 5 种类型,在现在的系统中每种类型只有一个设备。
enum android_alarm_type { /* return code bit numbers or set alarm arg */ ANDROID_ALARM_RTC_WAKEUP, ANDROID_ALARM_RTC, ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP, ANDROID_ALARM_ELAPSED_REALTIME, ANDROID_ALARM_SYSTEMTIME, ANDROID_ALARM_TYPE_COUNT, /* return code bit numbers */ /* ANDROID_ALARM_TIME_CHANGE = 16 */ };
alarm_queue struct alarm_queue { struct rb_root alarms; //红黑树的根 struct rb_node *first; //指向第一个 alarm device,即最早到时的 struct hrtimer timer; //内核定时器,android 利用它来确定 alarm 过期时间 ktime_t delta; //是一个计算 elasped realtime 的修正值 bool stopped; ktime_t stopped_time; };
这个结构体用于将前面的 struct alarm 表示的设备组织成红黑树。它是基于内核定时器 来实现 alarm 的到期闹铃的。
11.3 关键代码分析
alarm_dev.c
www.linuxidc.com
Linux公社(LinuxIDC.com) 是包括Ubuntu,Fedora,SUSE技术,最新IT资讯等Linux专业类网站。
该文件依赖于 alarm.c 提供的框架,实现了与应用层交互的功能,具体说就是暴露出 miscdevice 的设备接口。Alarm_dev.c 定义了几个全局变量:
每种类型一个 alarm 设备,android 目前创建了 5 个 alarm 设备。 static struct alarm alarms[ANDROID_ALARM_TYPE_COUNT];
wake lock 锁,当加锁时,阻止系统进 suspend 状态。 static struct wake_lock alarm_wake_lock;
标志位,alarm 设备是否被打开。 static int alarm_opened;
标志位,alarm 设备是否就绪。所谓就绪是指该 alarm 设备的闹铃时间到达,但原本等待在 该 alarm 设备上的进程还未唤醒,一旦唤醒,该标志清零。 static uint32_t alarm_pending;
标志位,表示 alarm 设备是否 enabled,表示该设备设置了闹铃时间(并且闹铃时间还未到) , 一旦闹铃时间到了,该标志清零。 static uint32_t alarm_enabled;
标志位,表示原先等待该 alarm 的进程被唤醒了(它们等待的 alarm 到时了)。 static uint32_t wait_pending; 该文件提供的主要函数有: 1,模块初始化和 exit 函数:alarm_dev_init 和 alarm_dev_exit 2,模块 miscdevice 标准接口函数:alarm_open、alarm_release 和 alarm_ioctl 3, alarm 定时时间到时候的回调函数:alarm_triggered
alarm_dev_init 初始化函数调用 misc_register 注册一个 miscdevice。 static int __init alarm_dev_init(void){ int err; int i;
err = misc_register(&alarm_device); if (err) return err;
for (i = 0; i < ANDROID_ALARM_TYPE_COUNT; i++) alarm_init(&alarms[i], i, alarm_triggered); wake_lock_init(&alarm_wake_lock, WAKE_LOCK_SUSPEND, "alarm");
return 0; }
该设备称为 alarm_device,定义如下: static struct miscdevice alarm_device = { .minor = MISC_DYNAMIC_MINOR, .name = "alarm", .fops = &alarm_fops, };
www.linuxidc.com
Linux公社(LinuxIDC.com) 是包括Ubuntu,Fedora,SUSE技术,最新IT资讯等Linux专业类网站。
对应的 file operations 为 alarm_fops,定义为: static const struct file_operations alarm_fops = { .owner = THIS_MODULE, .unlocked_ioctl = alarm_ioctl, .open = alarm_open, .release = alarm_release, };
然后为每个 alarm device 调用 alarm_init 初始化,这个函数代码在 alarm.c 中,如下: void alarm_init(struct alarm *alarm, enum android_alarm_type type, void (*function)(struct alarm *)){ RB_CLEAR_NODE(&alarm->node); alarm->type = type; alarm->function = function; pr_alarm(FLOW, "created alarm, type %d, func %pF\n", type, function); }
就是初始化 alarm 结构体,设置其回调函数为 alarm_triggered。最后调用 wake_lock_init 初 始化 alarm_wake_lock,它是 suspend 型的。alarm_triggered 是回调函数,当定时闹铃的时间 到了,alarm_timer_triggered 函数会调用该函数(详细请看 alarm.c 的 alarm_timer_triggered 函数)。
static void alarm_triggered(struct alarm *alarm){ unsigned long flags; uint32_t alarm_type_mask = 1U << alarm->type;
pr_alarm(INT, "alarm_triggered type %d\n", alarm->type); spin_lock_irqsave(&alarm_slock, flags); if (alarm_enabled & alarm_type_mask) { wake_lock_timeout(&alarm_wake_lock, 5 * HZ); alarm_enabled &= ~alarm_type_mask; alarm_pending |= alarm_type_mask; wake_up(&alarm_wait_queue); } spin_unlock_irqrestore(&alarm_slock, flags); }
这个函数里调用 wake_lock_timeout 对全局 alarm_wake_lock(超时锁,超时时间是 5 秒) 加锁,禁止对应的 alarm 设备。唤醒所有等待在该 alarm 设备上的进程。这时,如果 AP 层 呼叫 ioctl(fd, ANDROID_ALARM_WAIT),会返回表示等到 alarm 的返回值(这个会在 AlarmManagerSevice.java 中细述)。
alarm_ioctl 定义了以下命令: ANDROID_ALARM_CLEAR 清除 alarm,即 deactivate 这个 alarm ANDROID_ALARM_SET_OLD 设置 alarm 闹铃时间 ANDROID_ALARM_SET 同上 ANDROID_ALARM_SET_AND_WAIT_OLD 设置 alarm 闹铃时间并等待这个 alarm ANDROID_ALARM_SET_AND_WAIT 同上 ANDROID_ALARM_WAIT 等待 alarm ANDROID_ALARM_SET_RTC 设置 RTC 时间 ANDROID_ALARM_GET_TIME 读取 alarm 时间,根据 alarm 类型又分四种情况
www.linuxidc.com
Linux公社(LinuxIDC.com) 是包括Ubuntu,Fedora,SUSE技术,最新IT资讯等Linux专业类网站。
alarm.c 该文件完成主要功能有: 创建一个 alarm class,所有 alarm 设备都属于这个类; 注册了 platform driver,提供 suspend 和 resume 支持; 实 现 了 一 系 列 函 数 , 包 括 alarm_init , alarm_start_range , alarm_cancel , alarm_timer_triggered 函数等。
Alarm.c 的初始化函数 alarm_driver_init 如下: static int __init alarm_driver_init(void){ int err; int i;
for (i = 0; i < ANDROID_ALARM_SYSTEMTIME; i++) { hrtimer_init(&alarms[i].timer, CLOCK_REALTIME, HRTIMER_MODE_ABS); alarms[i].timer.function = alarm_timer_triggered; } hrtimer_init(&alarms[ANDROID_ALARM_SYSTEMTIME].timer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS); alarms[ANDROID_ALARM_SYSTEMTIME].timer.function = alarm_timer_triggered; err = platform_driver_register(&alarm_driver); if (err < 0) goto err1; wake_lock_init(&alarm_rtc_wake_lock, WAKE_LOCK_SUSPEND, "alarm_rtc"); rtc_alarm_interface.class = rtc_class; err = class_interface_register(&rtc_alarm_interface); if (err < 0) goto err2;
return 0;
err2: wake_lock_destroy(&alarm_rtc_wake_lock); platform_driver_unregister(&alarm_driver); err1: return err; }
该函数初始化 5 个 alarm device 相关联的 hrtimer 定时器,设置 hrtimer 定时器的回调函数为 alarm_timer_triggered 函数,再注册一个 plateform driver 和 class interface。 如果设置了闹 铃时间,则内核通过 hrtimer 定时器来跟踪是否到时间,到时后会触发调用 hrtimer 的处理 函数 alarm_timer_triggered。alarm_timer_triggered 的 code 如下:
www.linuxidc.com
Linux公社(LinuxIDC.com) 是包括Ubuntu,Fedora,SUSE技术,最新IT资讯等Linux专业类网站。
static enum hrtimer_restart alarm_timer_triggered(struct hrtimer *timer){ struct alarm_queue *base; struct alarm *alarm; unsigned long flags; ktime_t now;
spin_lock_irqsave(&alarm_slock, flags);
base = container_of(timer, struct alarm_queue, timer); now = base->stopped ? base->stopped_time : hrtimer_cb_get_time(timer); now = ktime_sub(now, base->delta);
pr_alarm(INT, "alarm_timer_triggered type %d at %lld\n", base - alarms, ktime_to_ns(now));
while (base->first) { alarm = container_of(base->first, struct alarm, node); if (alarm->softexpires.tv64 > now.tv64) { pr_alarm(FLOW, "don't call alarm, %pF, %lld (s %lld)\n", alarm->function, ktime_to_ns(alarm->expires), ktime_to_ns(alarm->softexpires)); break; } base->first = rb_next(&alarm->node); rb_erase(&alarm->node, &base->alarms); RB_CLEAR_NODE(&alarm->node); pr_alarm(CALL, "call alarm, type %d, func %pF, %lld (s %lld)\n", alarm->type, alarm->function, ktime_to_ns(alarm->expires), ktime_to_ns(alarm->softexpires)); spin_unlock_irqrestore(&alarm_slock, flags); alarm->function(alarm); spin_lock_irqsave(&alarm_slock, flags); } if (!base->first) pr_alarm(FLOW, "no more alarms of type %d\n", base - alarms); update_timer_locked(base, true); spin_unlock_irqrestore(&alarm_slock, flags); return HRTIMER_NORESTART; }
它会轮询红黑树中的所有 alarm 节点,符合条件的节点会执行 alarm.function(alarm),指向 alarm_dev.c 的 alarm_triggered 函数。因为我们在执行 alarm_dev.c 的 alarm_init 时,把每个 alarm 节点的 function 设置成了 alarm_triggered。
请注意这两个函数的区别,alarm_triggered 和 alarm_timer_triggered。前者是 rtc 芯片的 alarm 中断的回调函数,后者是 android alarm_queue->timer 到时的回调函数。
上面说到,alarm_driver_init 注册了一个类接口 class_interface_register(&rtc_alarm_interface)
rtc_alarm_interface 的 code 如下: static struct class_interface rtc_alarm_interface = { .add_dev = &rtc_alarm_add_device, .remove_dev = &rtc_alarm_remove_device, };
在 rtc_alarm_add_device 中,注册了一个 rtc 中断 rtc_irq_register(rtc,&alarm_rtc_task)
www.linuxidc.com
Linux公社(LinuxIDC.com) 是包括Ubuntu,Fedora,SUSE技术,最新IT资讯等Linux专业类网站。
static int rtc_alarm_add_device(struct device *dev, struct class_interface *class_intf){ int err; struct rtc_device *rtc = to_rtc_device(dev);
mutex_lock(&alarm_setrtc_mutex);
if (alarm_rtc_dev) { err = -EBUSY; goto err1; }
alarm_platform_dev = platform_device_register_simple("alarm", -1, NULL, 0); if (IS_ERR(alarm_platform_dev)) { err = PTR_ERR(alarm_platform_dev); goto err2; } err = rtc_irq_register(rtc, &alarm_rtc_task); if (err) goto err3; alarm_rtc_dev = rtc; pr_alarm(INIT_STATUS, "using rtc device, %s, for alarms", rtc->name); mutex_unlock(&alarm_setrtc_mutex);
return 0;
err3: platform_device_unregister(alarm_platform_dev); err2: err1: mutex_unlock(&alarm_setrtc_mutex); return err; }
中断的回调函数为 alarm_triggered_func: static struct rtc_task alarm_rtc_task = { .func = alarm_triggered_func };
static void alarm_triggered_func(void *p){ struct rtc_device *rtc = alarm_rtc_dev; if (!(rtc->irq_data & RTC_AF)) return; pr_alarm(INT, "rtc alarm triggered\n"); wake_lock_timeout(&alarm_rtc_wake_lock, 1 * HZ); } 当硬件 rtc chip 的 alarm 中断发生时,系统会调用 alarm_triggered_func 函数。 alarm_triggered_func 的功能很简单,wake_lock_timeout 锁住 alarm_rtc_wake_lock 1 秒。因 为这时,alarm 会进入 alarm_resume,lock 住 alarm_rtc_wake_lock 以防止 alarm 在此时进入 suspend。
AlarmManager.java,该文件提供的接口主要有: 设置闹钟 public void set(int type, long triggerAtTime, PendingIntent operation); 设置周期闹钟。 public void setRepeating(int type, long triggerAtTime, long interval,PendingIntent operation); 取消闹钟 public void cancel(PendingIntent operation);
www.linuxidc.com
Linux公社(LinuxIDC.com) 是包括Ubuntu,Fedora,SUSE技术,最新IT资讯等Linux专业类网站。
上面 3 个函数分别会呼叫到 AlarmManagerSevice.java 以下三个函数: public void set(int type, long triggerAtTime, PendingIntent operation); public void setRepeating(int type, long triggerAtTime, long interval,PendingIntent operation); public void remove(PendingIntent operation);
AlarmManagerSevice.java 通过 JNI 机制可以呼叫 com_android_server_AlarmManagerService.cpp 透出的几个接口。
AlarmManagerSevice.java 有关接口的 code 如下: private native int init(); private native void close(int fd); private native void set(int fd, int type, long seconds, long nanoseconds); private native int waitForAlarm(int fd); private native int setKernelTimezone(int fd, int minuteswest);
com_android_server_AlarmManagerService.cpp 有关接口的对应 code 如下: 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}, };
当 AP 呼叫 AlarmManager.java 的 set 或 setRepeating 函数时,最终会呼叫 com_android_server_AlarmManagerService.cpp 的 static void android_server_AlarmManagerService_set (JNIEnv* env, jobject obj, jint fd, jint type, jlong seconds, jlong nanoseconds) 在此函数中,会执行 ioctl(fd, ANDROID_ALARM_SET(type), &ts); 然后会呼叫到 alarm-dev.c 中 alarm_ioctl 中,接着 alarm-dev.c 会往它的红黑树中增加一个 alarm 节点。
在 AlarmManagerService 开始的时候,会启动一个 AlarmThread。在这个 AlarmThread 中有一 个 while 循环去执行 waitForAlarm 这个动作,这个函数最终通过 JNI 机制呼叫到 com_android_server_AlarmManagerService.cpp 的 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; }
www.linuxidc.com
Linux公社(LinuxIDC.com) 是包括Ubuntu,Fedora,SUSE技术,最新IT资讯等Linux专业类网站。
return result; #endif } 从 code 中可以看到,实际上它是在不断地执行 ioctl (fd,ANDROID_ALARM_WAIT),上面说 到,当闹钟到期时,alarm.c 中的 alarm_timer_triggered 函数会调用 alarm_triggered,这时, AP 层在呼叫 ioctl ( fd,ANDROID_ALARM_WAIT)时,会返回表示等到 alarm 的返回值。
所以当闹钟到期时,AlarmThread 的 waitForAlarm 会返回一个值。接着通过执行 triggerAlarmsLocked,把几种类型的闹钟列表中符合要求的 alarm 添加到 triggerList 中,然后 用 alarm.operation.send 发送消息,调起小闹钟程序。
AlarmThread 的 code 如下: private class AlarmThread extends Thread { public AlarmThread() { super("AlarmManager"); }
public void run() { while (true) { int result = waitForAlarm(mDescriptor); ArrayList<Alarm> triggerList = new ArrayList<Alarm>(); if ((result & TIME_CHANGED_MASK) != 0) { remove(mTimeTickSender); mClockReceiver.scheduleTimeTickEvent(); Intent intent = new Intent(Intent.ACTION_TIME_CHANGED); intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING); mContext.sendBroadcast(intent); } synchronized (mLock) { final long nowRTC = System.currentTimeMillis(); final long nowELAPSED = SystemClock.elapsedRealtime(); if (localLOGV) Slog.v( TAG, "Checking for alarms... rtc=" + nowRTC + ", elapsed=" + nowELAPSED);
if ((result & RTC_WAKEUP_MASK) != 0) triggerAlarmsLocked(mRtcWakeupAlarms, triggerList, nowRTC); if ((result & RTC_MASK) != 0) triggerAlarmsLocked(mRtcAlarms, triggerList, nowRTC); if ((result & ELAPSED_REALTIME_WAKEUP_MASK) != 0) triggerAlarmsLocked(mElapsedRealtimeWakeupAlarms, triggerList, nowELAPSED); if ((result & ELAPSED_REALTIME_MASK) != 0) triggerAlarmsLocked(mElapsedRealtimeAlarms, triggerList, nowELAPSED); // now trigger the alarms Iterator<Alarm> it = triggerList.iterator(); while (it.hasNext()) { Alarm alarm = it.next(); try { if (localLOGV) Slog.v(TAG, "sending alarm " + alarm); alarm.operation.send(mContext, 0,
www.linuxidc.com
Linux公社(LinuxIDC.com) 是包括Ubuntu,Fedora,SUSE技术,最新IT资讯等Linux专业类网站。
mBackgroundIntent.putExtra( Intent.EXTRA_ALARM_COUNT, alarm.count), mResultReceiver, mHandler); // we have an active broadcast so stay awake. if (mBroadcastRefCount == 0) { mWakeLock.acquire(); } mBroadcastRefCount++; BroadcastStats bs = getStatsLocked(alarm.operation); if (bs.nesting == 0) { bs.startTime = nowELAPSED; } else { bs.nesting++; } if (alarm.type == AlarmManager.ELAPSED_REALTIME_WAKEUP || alarm.type == AlarmManager.RTC_WAKEUP) { bs.numWakeup++; ActivityManagerNative.noteWakeupAlarm( alarm.operation); } } catch (PendingIntent.CanceledException e) { if (alarm.repeatInterval > 0) { remove(alarm.operation); } } catch (RuntimeException e) { Slog.w(TAG, "Failure sending alarm.", e); } } } } } }
11.4 接口
Android 中,Alarm 的操作通过 AlarmManager 来处理,AlarmManager 系统服务的具体实现 在:frameworks/base/services/java/com/android/server/AlarmManagerServic.java 文件中。应用 程序中可以通过 getSystemService 获得其系统服务,如下所示: AlarmManager alarms = (AlarmManager)getSystemService(Context.ALARM_SERVICE);
为了创建一个新的 Alarm,使用 set 方法并指定一个 Alarm 类型、触发时间和在 Alarm 触发 时要调用的 Intent。如果你设定的 Alarm 发生在过去,那么它将立即触发。
这里有 4 种 Alarm 类型。你的选择将决定你在 set 方法中传递的时间值代表什么,是特定的 时间或者是时间流逝:
RTC_WAKEUP:在指定的时刻(设置 Alarm 的时候),唤醒设备来触发 Intent。 RTC:在一个显式的时间触发 Intent,但不唤醒设备。 ELAPSED_REALTIME:从设备启动后,如果流逝的时间达到总时间,那么触发 Intent,但 不唤醒设备。流逝的时间包括设备睡眠的任何时间。注意一点的是,时间流逝的计算点 是自从它最后一次启动算起。 ELAPSED_REALTIME_WAKEUP:从设备启动后,达到流逝的总时间后,如果需要将唤醒 设备并触发 Intent。
www.linuxidc.com
Linux公社(LinuxIDC.com) 是包括Ubuntu,Fedora,SUSE技术,最新IT资讯等Linux专业类网站。
这 4 种 Alarm 类型详情请参考 frameworks/base/core/java/android/app/AlarmManager.java。
11.5 实例
最后,请看一个 Alarm 的实例: 1、 建立一个 AlarmReceiver 继承入 BroadcastReceiver,并在 AndroidManifest.xml 声明 Public static class AlarmReceiver extends BroadcastReceiver { @Override Public void onReceive (Context context, Intent intent) { Toast.makeText(context, “时间到”, Toast.LENGTH_LONG).show(); } }
2、 建立 Intent 和 PendingIntent,来调用目标组件。 Intent it = new Intent(this, AlarmReceiver.class); PendingIntent pi = PendingIntent.getBroadcast(this, 0, intent, 0);
3、 设置闹钟 获取闹钟管理的实例: AlarmManager am = (AlarmManager)getSystemService(Context.ALARM_SERVICE);
设置单次闹钟: am.set(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + (5*1000), pi);
设置周期闹钟: am.setRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + (10*1000), (24*60*60*1000), pi);
第十一章 Android 内核驱动——Alarm的更多相关文章
- 《Android群英传》读书笔记 (5) 第十一章 搭建云端服务器 + 第十二章 Android 5.X新特性详解 + 第十三章 Android实例提高
第十一章 搭建云端服务器 该章主要介绍了移动后端服务的概念以及Bmob的使用,比较简单,所以略过不总结. 第十三章 Android实例提高 该章主要介绍了拼图游戏和2048的小项目实例,主要是代码,所 ...
- 《Linux内核设计与实现》第五周读书笔记——第十一章
<Linux内核设计与实现>第五周读书笔记——第十一章 20135301张忻 估算学习时间:共2.5小时 读书:2.0 代码:0 作业:0 博客:0.5 实际学习时间:共3.0小时 读书: ...
- NVDLA软件架构和源码解析 第一章—内核驱动【华为云技术分享】
驱动整体设计介绍 不同的processor Nvidia DLA的内核驱动KMD(Kernel mode driver)中,并不是把DLA当成一个设备来控制,而是把不同的功能模块当做不同的proces ...
- Android内核驱动程序的编写和编译过程
注意:涉及的代码为android内核代码而不是android源码. 在智能手机时代,每个品牌的手机都有自己的个性特点.正是依靠这种与众不同的个性来吸引用户,营造品牌凝聚力和用户忠城度,典型的代表非ip ...
- Android进阶加密-第1章-Android系统架构-读书笔记
第 1 章 Android 系统架构 1.1 Android 系统架构 Android 系统架构分为五层,从上到下依次是应用层.应用框架层.系统运行库层.硬件抽象层和 Linux 内核层. 应用层(S ...
- 第一章 Android系统的编译和移植实例
第一章 Android系统的编译和移植实例 这一章节主要介绍了Android系统的编译和移植技术,作为建立在Linux内核的基础上的Android操作系统,它的编译和移植不论在过程还是技术方面都和嵌入 ...
- 精通Web Analytics 2.0 (13) 第十一章:变身分析忍者的指导原则
精通Web Analytics 2.0 : 用户中心科学与在线统计艺术 第十一章:变身分析忍者的指导原则 这个激动人心的一章,分析了几乎所有工作的各个方面. 目标很简单:使用成熟的方法来帮助避免淹死的 ...
- 《深入理解Android内核设计思想》
<深入理解Android内核设计思想> 基本信息 作者: 林学森 出版社:人民邮电出版社 ISBN:9787115348418 上架时间:2014-4-25 出版日期:2014 年5月 开 ...
- Android内核和Linux内核的区别
1.Android系统层面的底层是Linux,并且在中间加上了一个叫做Dalvik的Java虚拟机,从表面层看是Android运行库.每个Android应用都运行在自己的进程上,享有Dalvik虚拟机 ...
随机推荐
- 使用mysql 的docker
sudo docker run --name phpmyAdmin3 --link some-mysql:mysql -d phpmyadmin/phpmyadmin:latest -p 8080:8 ...
- Android 开发环境搭建以及编译
两种搭建编译环境的方式,一种方法是用户安装虚拟机,然后安装基础的Ubuntu12.04.2 系统,利用提供的工具和详细的使用步骤,搭建编译环境:另外一种方法是用户安装虚拟机,然后直接加载 “搭建好的U ...
- SQLSERVER:Timeout expired. The timeout period elapsed prior to obtaining a connection from the pool. This may have occurred because all pooled connections were in use and max pool size was reached.
背景: 在最近开发中遇到一个问题,对一个数据库进行操作时,我采用64个并行的任务每个任务保证一个数据库连接对象:但是每个任务内部均包含有24个文件需要读取,在读取文件之后,我们需要快速将这24个文件批 ...
- zoj The 12th Zhejiang Provincial Collegiate Programming Contest Team Formation
http://acm.zju.edu.cn/onlinejudge/showContestProblem.do?problemId=5494 The 12th Zhejiang Provincial ...
- WOW: 宏
1.常用的宏命令 1.1常用的宏命令 1.释放技能命令 /cast 释放一个或多个技能,可以加入一些条件判断,是最常用的命令 /castsequence 依次释放释放数个技能,同样可以加入一些条件判断 ...
- C++初学者 const使用详解
关于C++中的const关键字的用法非常灵活,而使用const将大大改善程序的健壮性,参考了康建东兄的const使用详解一文,对其中进行了一些补充,写下了本文. 1. const常量 如: cons ...
- paper 10:支持向量机系列七:Kernel II —— 核方法的一些理论补充,关于 Reproducing Kernel Hilbert Space 和 Representer Theorem 的简介。
在之前我们介绍了如何用 Kernel 方法来将线性 SVM 进行推广以使其能够处理非线性的情况,那里用到的方法就是通过一个非线性映射 ϕ(⋅) 将原始数据进行映射,使得原来的非线性问题在映射之后的空间 ...
- Java中的数组操作进阶
package com.mi.array; import java.util.Arrays; /** * System.arraycopy(i, 0, j, 0, i.length);这种复制会覆盖目 ...
- javascript 操作dom
Node往往被翻译为节点,在一个对象(可以简单的理解为是HTML页面中),一个属性name="aaa"可以是一个节点,一个< div id="aaa"&g ...
- 机器学习实战5:k-means聚类:二分k均值聚类+地理位置聚簇实例
k-均值聚类是非监督学习的一种,输入必须指定聚簇中心个数k.k均值是基于相似度的聚类,为没有标签的一簇实例分为一类. 一 经典的k-均值聚类 思路: 1 随机创建k个质心(k必须指定,二维的很容易确定 ...