轉載: http://blog.csdn.net/hovan/article/details/42495379

下面是简单的流程图,从Java到kernel层。

ShutdownThread.java文件

stop playing music,因为后面可能要playing shutdown music.

代码如下:(我在Android6.0上沒有看到調用requestAudioFocus的代碼)

    private static void beginShutdownSequence(Context context) {  ....  //acquire audio focus to make the other apps to stop playing muisc  mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);  mAudioManager.requestAudioFocus(null,  AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN);  

show system dialog to indicate phone is shutting down,如果没有关机动画的话,要show一个关机提示出来。

代码如下:

 1     if (!checkAnimationFileExist()) {
 2         // throw up an indeterminate system dialog to indicate radio is
 3         // shutting down.
 4         ProgressDialog pd = new ProgressDialog(context);
 5         pd.setTitle(context.getText(com.android.internal.R.string.power_off));
 6         pd.setMessage(context.getText(com.android.internal.R.string.shutdown_progress));
 7         pd.setIndeterminate(true);
 8         pd.setCancelable(false);
 9         pd.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
10
11         pd.show();
12     }  

Hold the wakelock,make sure we never fall asleep again,抓锁防止机器关机过程中休眠

代码如下:

1     sInstance.mCpuWakeLock = sInstance.mPowerManager.newWakeLock(
2             PowerManager.PARTIAL_WAKE_LOCK, TAG + "-cpu");//这个只是锁住cpu不进入休眠,但screen是off的,需full锁来保证screen常亮
3     sInstance.mCpuWakeLock.setReferenceCounted(false);
4     sInstance.mCpuWakeLock.acquire();  

make sure the screen stays on,再抓一个full锁,防止屏幕半暗

代码如下:

1     sInstance.mScreenWakeLock = sInstance.mPowerManager.newWakeLock(
2             PowerManager.FULL_WAKE_LOCK, TAG + "-screen");//保持srceen常亮
3     sInstance.mScreenWakeLock.setReferenceCounted(false);
4     sInstance.mScreenWakeLock.acquire();  

sending shutdown broadcast,发出广播,通知各app该保存数据赶紧的,我要关机了

代码如下:

1     Intent intent = new Intent(Intent.ACTION_SHUTDOWN);
2     intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
3     mContext.sendOrderedBroadcastAsUser(intent,//发广播
4             UserHandle.ALL, null, br, mHandler, 0, null, null);  

shutdown activity manager,关闭activity manager,即关闭AppOpsService,UsageStatsService,BatteryStatsService

注意:Android L 与KK在关闭UsageStatsService上有所区别

代码如下:

[ActivityManagerService.java]

1     final IActivityManager am =
2                 ActivityManagerNative.asInterface(ServiceManager.checkService("activity"));
3             if (am != null) {
4                 try {
5                     am.shutdown(MAX_BROADCAST_TIME);
6                 } catch (RemoteException e) {
7                 }
8             }  

shutdown package manager,保存app使用时间到 disk里,这是android L新增的功能。

代码如下:

[PackageManagerService.java]

1     final PackageManagerService pm = (PackageManagerService)
2         ServiceManager.getService("package");
3     if (pm != null) {
4         pm.shutdown();
5     }  

show shutdown animation,播放关机动画了

代码如下:

 1     private static void showShutdownAnimation() {
 2         /*
 3          * When boot completed, "service.bootanim.exit" property is set to 1.
 4          * Bootanimation checks this property to stop showing the boot animation.
 5          * Since we use the same code for shutdown animation, we
 6          * need to reset this property to 0. If this is not set to 0 then shutdown
 7          * will stop and exit after displaying the first frame of the animation
 8          */
 9         SystemProperties.set("service.bootanim.exit", "0");
10
11         SystemProperties.set("ctl.start", "bootanim");//也是用bootanim进程,跟开关动画一样的方式。
12     }  

shutdown radio[NFC,BT,MODEM],注意这里关闭modem这块与andorid KK的不一样。

代码如下:

shutdownRadios(MAX_RADIO_WAIT_TIME);

shutdown MountService,特别这里会导致关机失败。

代码如下:

 1     // Set initial variables and time out time.
 2     mActionDone = false;
 3     final long endShutTime = SystemClock.elapsedRealtime() + MAX_SHUTDOWN_WAIT_TIME;
 4     synchronized (mActionDoneSync) {
 5         try {
 6             final IMountService mount = IMountService.Stub.asInterface(
 7                     ServiceManager.checkService("mount"));
 8             if (mount != null) {
 9                 mount.shutdown(observer);
10             } else {
11                 Log.w(TAG, "MountService unavailable for shutdown");
12             }
13         } catch (Exception e) {
14             Log.e(TAG, "Exception during MountService shutdown", e);
15         }
16         while (!mActionDone) {
17             long delay = endShutTime - SystemClock.elapsedRealtime();
18             if (delay <= 0) {
19                 Log.w(TAG, "Shutdown wait timed out");
20                 break;
21             }
22             try {
23                 mActionDoneSync.wait(delay);
24             } catch (InterruptedException e) {
25             }
26         }
27     }  

走完上层关机流程,下面就要执行关机动作了。

代码如下:

 1     public static void rebootOrShutdown(boolean reboot, String reason) {
 2         deviceRebootOrShutdown(reboot, reason);
 3         if (reboot) {
 4             Log.i(TAG, "Rebooting, reason: " + reason);
 5             PowerManagerService.lowLevelReboot(reason);//重启, 其中reason字符串可以爲空、“bootloader”、“recovery”, 在手機下次啓動中LK會根據這些值使手機進入不同的模式
 6             Log.e(TAG, "Reboot failed, will attempt shutdown instead");
 7         } else if (SHUTDOWN_VIBRATE_MS > 0) {
 8             // vibrate before shutting down
 9             Vibrator vibrator = new SystemVibrator();
10             try {
11                 vibrator.vibrate(SHUTDOWN_VIBRATE_MS, VIBRATION_ATTRIBUTES);
12             } catch (Exception e) {
13                 // Failure to vibrate shouldn't interrupt shutdown.  Just log it.
14                 Log.w(TAG, "Failed to vibrate during shutdown.", e);
15             }
16
17             // vibrator is asynchronous so we need to wait to avoid shutting down too soon.
18             try {
19                 Thread.sleep(SHUTDOWN_VIBRATE_MS);
20             } catch (InterruptedException unused) {
21             }
22         }
23
24         // Shutdown power
25         Log.i(TAG, "Performing low-level shutdown...");
26         PowerManagerService.lowLevelShutdown();//关机
27     }  

从代码上看始终会走到lowLevelShutdown(),但如果是重启就不会,lowLevelReboot()就停止了。

lowLevelShutdown()与lowLevelReboot()都在PowerManagerService.java实现,其实都只是设置一个属性:SystemProperties.set("sys.powerctl", "xxx");

正是这个动作触发关机流程往下走,这涉及到init进程的4大功能,请参考我的另一篇文章Android的init进程

sys.powerctl属性触发开关在init.rc定义

    on property:sys.powerctl=*  powerctl ${sys.powerctl}  

我们来解读这句话,on property:sys.powerctl=*表示当属性sys.powerctl设置为任何值是都会跑到这里,触发动作是powerctl ${sys.powerctl},这个动作的意思是调用powerctl指令,并把sys.powerctl的值传给它。powerctl指令在init 进程会执行。

从下面的表可知,powerctl对应的操作是do_powerctl

[system/core/init/keywords.h]

KEYWORD(powerctl,    COMMAND, 1, do_powerctl)  

do_powerctl的实现

代码如下:

[system/core/init/builtins.c]

 1 int do_powerctl(int nargs, char **args)
 2 {
 3     char command[PROP_VALUE_MAX];
 4     int res;
 5     int len = 0;
 6     int cmd = 0;
 7     const char *reboot_target;
 8
 9     res = expand_props(command, args[1], sizeof(command));  //args中存放的是: shutdown 或者 reboot 或者 reboot,bootloader 或者 reboot,recovery
10     if (res) {
11         ERROR("powerctl: cannot expand '%s'\n", args[1]);
12         return -EINVAL;
13     }
14
15     if (strncmp(command, "shutdown", 8) == 0) {
16         cmd = ANDROID_RB_POWEROFF;
17         len = 8;
18     } else if (strncmp(command, "reboot", 6) == 0) {
19         cmd = ANDROID_RB_RESTART2;
20         len = 6;
21     } else {
22         ERROR("powerctl: unrecognized command '%s'\n", command);
23         return -EINVAL;
24     }
25
26     if (command[len] == ',') {
27         char prop_value[PROP_VALUE_MAX] = {0};
28         reboot_target = &command[len + 1];  // 存放reboot的reason,也就是下次手機重啓將要進入的模式
29
30         if ((property_get("init.svc.recovery", prop_value) == 0) &&
31             (strncmp(reboot_target, "keys", 4) == 0)) {
32             ERROR("powerctl: permission denied\n");
33             return -EINVAL;
34         }
35     } else if (command[len] == '\0') {  // 如果reason爲空,對於reboot來說,下次手機會正常啓機
36         reboot_target = "";
37     } else {
38         ERROR("powerctl: unrecognized reboot target '%s'\n", &command[len]);
39         return -EINVAL;
40     }
41
42     return android_reboot(cmd, 0, reboot_target);
43 }

它调用android_reboot()函数,实现如下:

[system/core/libcutils/android_reboot.c]

 1 int android_reboot(int cmd, int flags UNUSED, const char *arg)
 2 {
 3     int ret;
 4
 5     sync();
 6     remount_ro();
 7
 8     switch (cmd) {
 9         case ANDROID_RB_RESTART:
10             ret = reboot(RB_AUTOBOOT);
11             break;
12
13         case ANDROID_RB_POWEROFF:
14             ret = reboot(RB_POWER_OFF);
15             break;
16
17         case ANDROID_RB_RESTART2:  // arg中存放的是reboot的reason,如bootloader、recovery
18             ret = syscall(__NR_reboot, LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2,
19                            LINUX_REBOOT_CMD_RESTART2, arg);
20             break;
21
22         default:
23             ret = -1;
24     }
25
26     return ret;
27 }

从这里看出它的主要工作:

sync() 回写block设备的内容,这是阻塞型操作。

remount_ro() 把block设备remount成ro,这里有个关键LOG:SysRq : Emergency Remount R/O,这是在logkit所能看到的最后一句LOG,因为remount成ro了,后面的LOG要通过last kmsg技术导出来。

reboot()或者syscall(__NR_reboot....,这点与android KK不同,这边直接用syscall功能,KK则通过汇编。

后面syscall(__NR_reboot...知道,直接调用了linux的__NR_reboot系统调用,这个系统调用会跑哪里?后面会讲。

reboot()这个函数实现如下:

[bionic/libc/bionic/reboot.cpp]

1     int reboot(int mode) {
2       return __reboot(LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, mode, NULL);
3     }  

调用了__reboot,它在汇编实现 如下:

[bionic/libc/arch-arm/syscalls/__reboot.S]

 1     ENTRY(__reboot)
 2         mov     ip, r7
 3         ldr     r7, =__NR_reboot      //也跑到__NR_reboot系统调用
 4         swi     #0
 5         mov     r7, ip
 6         cmn     r0, #(MAX_ERRNO + 1)
 7         bxls    lr
 8         neg     r0, r0
 9         b       __set_errno_internal
10     END(__reboot)  

__NR_reboot对应的内核入口在哪里?

如下:

[bionic/libc/kernel/uapi/asm-generic/unistd.h]

    #define __NR_reboot 142  

它在内核入口如下:

注:bionic/libc/kernel/uapi/asm-generic/unistd.h与kernel/include/uapi/asm-generic/unistd.h是对应的,方便以后代码追踪

[kernel/include/uapi/asm-generic/unistd.h]

1     #define __NR_reboot 142
2     __SYSCALL(__NR_reboot, sys_reboot)  

__NR_reboot 映射到 sys_reboot

grep 下sys_reboot 找不到,其实在这里

用SYSCALL_DEFINE定义

[kernel/kernel/reboot.c]

 1 /*
 2  * Reboot system call: for obvious reasons only root may call it,
 3  * and even root needs to set up some magic numbers in the registers
 4  * so that some mistake won't make this reboot the whole machine.
 5  * You can also set the meaning of the ctrl-alt-del-key here.
 6  *
 7  * reboot doesn't sync: do that yourself before calling this.
 8  */
 9 SYSCALL_DEFINE4(reboot, int, magic1, int, magic2, unsigned int, cmd,
10         void __user *, arg)
11 {
12     struct pid_namespace *pid_ns = task_active_pid_ns(current);
13     char buffer[256];
14     int ret = 0;
15
16     /* We only trust the superuser with rebooting the system. */
17     if (!ns_capable(pid_ns->user_ns, CAP_SYS_BOOT))
18         return -EPERM;
19
20     /* For safety, we require "magic" arguments. */
21     if (magic1 != LINUX_REBOOT_MAGIC1 ||
22             (magic2 != LINUX_REBOOT_MAGIC2 &&
23             magic2 != LINUX_REBOOT_MAGIC2A &&
24             magic2 != LINUX_REBOOT_MAGIC2B &&
25             magic2 != LINUX_REBOOT_MAGIC2C))
26         return -EINVAL;
27
28     /*
29      * If pid namespaces are enabled and the current task is in a child
30      * pid_namespace, the command is handled by reboot_pid_ns() which will
31      * call do_exit().
32      */
33     ret = reboot_pid_ns(pid_ns, cmd);
34     if (ret)
35         return ret;
36
37     /* Instead of trying to make the power_off code look like
38      * halt when pm_power_off is not set do it the easy way.
39      */
40     if ((cmd == LINUX_REBOOT_CMD_POWER_OFF) && !pm_power_off)
41         cmd = LINUX_REBOOT_CMD_HALT;
42
43     mutex_lock(&reboot_mutex);
44     switch (cmd) {
45     case LINUX_REBOOT_CMD_RESTART:
46         kernel_restart(NULL);
47         break;
48
49     case LINUX_REBOOT_CMD_CAD_ON:
50         C_A_D = 1;
51         break;
52
53     case LINUX_REBOOT_CMD_CAD_OFF:
54         C_A_D = 0;
55         break;
56
57     case LINUX_REBOOT_CMD_HALT:
58         kernel_halt();
59         do_exit(0);
60         panic("cannot halt");
61
62     case LINUX_REBOOT_CMD_POWER_OFF:
63         kernel_power_off();
64         do_exit(0);
65         break;
66
67     case LINUX_REBOOT_CMD_RESTART2:
68         ret = strncpy_from_user(&buffer[0], arg, sizeof(buffer) - 1);
69         if (ret < 0) {
70             ret = -EFAULT;
71             break;
72         }
73         buffer[sizeof(buffer) - 1] = '\0';
74
75         kernel_restart(buffer);
76         break;
77
78 #ifdef CONFIG_KEXEC
79     case LINUX_REBOOT_CMD_KEXEC:
80         ret = kernel_kexec();
81         break;
82 #endif
83
84 #ifdef CONFIG_HIBERNATION
85     case LINUX_REBOOT_CMD_SW_SUSPEND:
86         ret = hibernate();
87         break;
88 #endif
89
90     default:
91         ret = -EINVAL;
92         break;
93     }
94     mutex_unlock(&reboot_mutex);
95     return ret;
96 }

有很多分支,我们只关心kernel_power_off()和kernel_restart()两函数就行

如下:

kernel_power_off:

 1     void kernel_power_off(void)
 2     {
 3         kernel_shutdown_prepare(SYSTEM_POWER_OFF);//关闭外设
 4         if (pm_power_off_prepare)
 5             pm_power_off_prepare();
 6         migrate_to_reboot_cpu();   // 比如執行reboot命令的進程運行在CPU1上,而將來CPU1會先於CPU0被停止,故需要將當前進程轉移至CPU0上
 7         syscore_shutdown();//关闭syscore
 8         printk(KERN_EMERG "Power down.\n");//关键打印
 9         kmsg_dump(KMSG_DUMP_POWEROFF);
10         machine_power_off();
11     }  

kernel_restart:

 1     void kernel_restart(char *cmd)
 2     {
 3         kernel_restart_prepare(cmd);//关闭外设
 4         migrate_to_reboot_cpu();
 5         syscore_shutdown();//关闭syscore
 6         if (!cmd)
 7             printk(KERN_EMERG "Restarting system.\n");//关键打印
 8         else
 9             printk(KERN_EMERG "Restarting system with command '%s'.\n", cmd);
10         kmsg_dump(KMSG_DUMP_RESTART);
11         machine_restart(cmd);
12     }  

都执行XX_prepare()函数

1     static void kernel_shutdown_prepare(enum system_states state)
2     {
3         blocking_notifier_call_chain(&reboot_notifier_list,
4             (state == SYSTEM_HALT)?SYS_HALT:SYS_POWER_OFF, NULL);
5         system_state = state;
6         usermodehelper_disable();
7         device_shutdown();
8     }  

上面的第3行會遍歷reboot_notifier_list鏈表,向其中註冊的每一個notifier_block發送SYS_POWER_OFF事件。

在我們的驅動程序中可以調用如下函數將notifier_block註冊到系統中:

 1 /**
 2  *    register_reboot_notifier - Register function to be called at reboot time
 3  *    @nb: Info about notifier function to be called
 4  *
 5  *    Registers a function with the list of functions
 6  *    to be called at reboot time.
 7  *
 8  *    Currently always returns zero, as blocking_notifier_chain_register()
 9  *    always returns zero.
10  */
11 int register_reboot_notifier(struct notifier_block *nb)
12 {
13     return blocking_notifier_chain_register(&reboot_notifier_list, nb);
14 }
15 EXPORT_SYMBOL(register_reboot_notifier);

在第7行中調用了device_shutdown()函數,如下:

 1 /**
 2  * device_shutdown - call ->shutdown() on each device to shutdown.
 3  */
 4 void device_shutdown(void)
 5 {
 6     struct device *dev, *parent;
 7
 8     spin_lock(&devices_kset->list_lock);
 9     /*
10      * Walk the devices list backward, shutting down each in turn.
11      * Beware that device unplug events may also start pulling
12      * devices offline, even as the system is shutting down.
13      */
14     while (!list_empty(&devices_kset->list)) {
15         dev = list_entry(devices_kset->list.prev, struct device,
16                 kobj.entry);
17                 ......
18
19         if (dev->bus && dev->bus->shutdown) {   // 如 i2c_bus_type
20             if (initcall_debug)
21                 dev_info(dev, "shutdown\n");
22             dev->bus->shutdown(dev);
23         } else if (dev->driver && dev->driver->shutdown) {  // 如spi_bus_type、usb_bus_type
24             if (initcall_debug)
25                 dev_info(dev, "shutdown\n");
26             dev->driver->shutdown(dev);
27         }
28                 ......
29     }
30     spin_unlock(&devices_kset->list_lock);
31 }
32                         

kernel_restart_prepare:

1     void kernel_restart_prepare(char *cmd)
2     {
3         blocking_notifier_call_chain(&reboot_notifier_list, SYS_RESTART, cmd);
4         system_state = SYSTEM_RESTART;
5         usermodehelper_disable();
6         device_shutdown();
7     }  

除了前面不同,都调用了device_shutdown()函数,关闭外设。

machine_power_off() machine_resestart()函数实现

machine_power_off:

1     void machine_power_off(void)
2     {
3         preempt_disable();
4         smp_send_stop();
5
6         if (pm_power_off)
7             pm_power_off();//关机
8     }  

其中,第4行的smp_send_stop會將除CPU0之外的CPU全部stop。

machine_restart:

 1     void machine_restart(char *cmd)
 2     {
 3         preempt_disable();
 4         smp_send_stop();
 5
 6         /* Flush the console to make sure all the relevant messages make it
 7          * out to the console drivers */
 8         arm_machine_flush_console();
 9
10         arm_pm_restart(reboot_mode, cmd);//重启
11
12         /* Give a grace period for failure to restart of 1s */
13         mdelay(1000);
14
15         /* Whoops - the platform was unable to reboot. Tell the user! */
16         printk("Reboot failed -- System halted\n");
17         local_irq_disable();
18         while (1);
19     }  

pm_power_offf() arm_pm_restart()都是一个函数指针

赋值如下:

[kernel/drivers/power/reset/msm-poweroff.c]

1     pm_power_off = do_msm_poweroff;
2     arm_pm_restart = do_msm_restart;  

高通平台的关机代码与之前有所不同,现在文件msm-poweroff.c以前是restart.c。

do_msm_poweroff()与do_msm_restart()实现如下:

do_msm_poweroff:

 1     static void do_msm_poweroff(void)
 2     {
 3     ....
 4         pr_notice("Powering off the SoC\n");//关键打印
 5     #ifdef CONFIG_MSM_DLOAD_MODE
 6         set_dload_mode(0);//关机,所以dloadmode是0
 7     #endif
 8         qpnp_pon_system_pwr_off(PON_POWER_OFF_SHUTDOWN);//配置PMIC,是关机
 9     .....
10         /* MSM initiated power off, lower ps_hold */
11         __raw_writel(0, msm_ps_hold);//拉 PS_HOLD,执行关机动作。
12
13         mdelay(10000);
14         pr_err("Powering off has failed\n");
15         return;
16     }  

do_msm_restart:

 1     static void do_msm_restart(enum reboot_mode reboot_mode, const char *cmd)
 2     ...
 3
 4         pr_notice("Going down for restart now\n");//关键打印
 5
 6         msm_restart_prepare(cmd);//重启准备前动作
 7
 8     #ifdef CONFIG_MSM_DLOAD_MODE
 9         /*
10          * Trigger a watchdog bite here and if this fails,
11          * device will take the usual restart path.
12          */
13
14         if (WDOG_BITE_ON_PANIC && in_panic)
15             msm_trigger_wdog_bite();
16     #endif
17
18     ....
19         halt_spmi_pmic_arbiter();
20         __raw_writel(0, msm_ps_hold);//拉PS_HOLD重启
21
22         mdelay(10000);
23     }  

msm_restart_prepare()实现

 1     static void msm_restart_prepare(const char *cmd)
 2     {
 3     #ifdef CONFIG_MSM_DLOAD_MODE
 4
 5         /* Write download mode flags if we're panic'ing
 6          * Write download mode flags if restart_mode says so
 7          * Kill download mode if master-kill switch is set
 8          */
 9
10         set_dload_mode(download_mode &&
11                 (in_panic || restart_mode == RESTART_DLOAD));//设置dload
12     #endif
13
14         /* Hard reset the PMIC unless memory contents must be maintained. */
15         if (get_dload_mode() || (cmd != NULL && cmd[0] != '\0'))
16             qpnp_pon_system_pwr_off(PON_POWER_OFF_WARM_RESET);//设置PIMC为热重启
17         else
18             qpnp_pon_system_pwr_off(PON_POWER_OFF_HARD_RESET);//设置PIMC为硬重启
19
20         if (cmd != NULL) {
21             if (!strncmp(cmd, "bootloader", 10)) {
22                 __raw_writel(0x77665500, restart_reason);//写一些东东到IMEM,用于bootloader,recovery等
23             } else if (!strncmp(cmd, "recovery", 8)) {
24                 __raw_writel(0x77665502, restart_reason);
25             } else if (!strcmp(cmd, "rtc")) {
26                 __raw_writel(0x77665503, restart_reason);
27             } else if (!strncmp(cmd, "oem-", 4)) {
28                 unsigned long code;
29                 int ret;
30                 ret = kstrtoul(cmd + 4, 16, &code);
31                 if (!ret)
32                     __raw_writel(0x6f656d00 | (code & 0xff),
33                              restart_reason);
34             } else if (!strncmp(cmd, "edl", 3)) {
35                 enable_emergency_dload_mode();
36             } else {
37                 __raw_writel(0x77665501, restart_reason);
38             }
39         }
40
41     .....
42
43     }  

do_msm_poweroff()与do_msm_restart()都设置了dload,PMIC,唯一不同的是do_msm_restart()里 多了一个__raw_writel的动作,即reason写入IMEM,目的在于重启进入sbl1时判断应该进入那种模式,如我们开发用的 bootloader模式,恢复出厂设置的recovery模式等。

完了

android L 关机流程图相关推荐

  1. 更新ADT到Android L的方法

    android ADT无法更新到20? 哈哈,有办法,windows 进入host   写入例如以下所有,是的所有.然后在到sdk manager中方可更新 #Google Services STAR ...

  2. 不仅是 64 位 Android L 还有这 9 大亮点

    Android L无疑是谷歌今年最重要的新产品之一,其战略意义重大,代表着谷歌统一多种设备平台的决心.显然,Android L有很多值得我们期待和兴奋的地方,以下是最主要的9点: Material D ...

  3. Android L 新特性

    转自:http://blog.jobbole.com/73577/ 每次Android新版的发布,Google都会发布一个API变更报告,概括出对比前一个版本增加.改变.移除的API等信息. 无论如何 ...

  4. Android L 仍需改善的三个问题

    Android L是谷歌今年交出的答卷之一,除了采用新的设计语言,还横跨Android Wear.TV等多个平台,并收紧了部分平台的界面定制权限,可以了解到谷歌在移动平台上的一些战略变化.当然,就设计 ...

  5. ubuntu1604编译android5.1(android L)失败error: unsupportedreloc 43等问题

    ubuntu1604编译android5.1(android L)失败error: unsupportedreloc 43等问题 1.    编译的问题 见session_root1 prebuilt ...

  6. [Android L]SEAndroid开放设备文件结点权限(读或写)方法(涵盖常用操作:sys/xxx、proc/xxx、SystemProperties)热门干货

    点击打开链接 温馨提示      建议你先了解一下上一篇博文([Android L]SEAndroid增强Androd安全性背景概要及带来的影响)所讲的内容,先对SEAndroid窥个全貌,然后再继续 ...

  7. 基于MT6752/32平台 Android L版本驱动移植步骤

    基于MT6752/32平台 Android L版本驱动移植步骤 根据MK官网所述,在Android L 版本上Turnkey ABS 架构将会phase out,而Mediatek Turnkey架构 ...

  8. Android L 使用ART能提高多少性能?

    点击打开链接 刚刚结束的 Google I/O 大会上,Android 下一代操作系统「L」带来不少惊喜.新系统运行更快.更省电. 然而开发者对这个新系统也有颇多疑问,比如新的运行模式 ART 对开发 ...

  9. 浅谈新一代Android操作系统Android L

    今天早一些的时候,Google发布了新一代Android操作系统Android L.让我非常意外的是命名规则的变化,之前外界纷纷猜测会叫Android5.0,同时会给一个甜品的名字命名.因为Andro ...

最新文章

  1. struts2 获取request、session的方法
  2. zookeeper3.4.6安装
  3. 在android studio中配置ndk开发环境
  4. 自制H3C交换机CONSOLE线
  5. 数据vs.算法,究竟谁更重要
  6. 会议 | 2019 全国知识图谱与语义大会 (CCKS 2019)
  7. 读取配置文件工程src目录下配置文件封装,如sms_format.properties
  8. 小程序直播 OBS 画质_微信小程序怎么直播卖货?
  9. [论文阅读] Learning Without Forgetting
  10. spring boot 全局异常处理的实现(@ExceptionHandler),以及@InitBinder、@ModelAttribute的作用
  11. 中国软件离制造业还是太远
  12. 国产性能最稳定NFC读卡器芯片FSV9520完美替代CV520 SPI接口 可免费提供软硬件DEMO 快速研发产品
  13. grldr文件引导windows xp、ubuntu系统
  14. 人物拼图java_JAVA实现拼图游戏
  15. 《吃透MQ系列,图灵学院和咕泡学院
  16. 如何搭建Telegram群机器人
  17. 写给成为高手之路上的朋友们
  18. word(1):word插入参考文献/引文并更新参考文献/引文编号
  19. mysql 添加字段并设置为自增长
  20. jQueryDom和源生DOM相互的转换、jQuery选择器语法、JQuery层次选择器语法、jQuery属性选择器语法、jQuery伪类选择器语法、

热门文章

  1. c#/.net 循序渐进理解-委托
  2. 课程名称翻译大全(zz)
  3. 数据类型与数据传送指令
  4. ROS学习(十二):ROS URDF-model_state
  5. LeetCode算法题9:递归和回溯-N皇后问题
  6. 最短路径(Dijkstra算法)(c/c++)
  7. iOS 仿看了吗应用、指南针测网速等常用工具、自定义弹出视图框架、图片裁剪、内容扩展等源码...
  8. kafka 在阿里云部署
  9. 编译安装Ruby 1.9.3 安装CentOS
  10. ZOJ-2571 Big String Outspread 模拟