deepin系统启动流程

deepin系统整个的启动流程到底是怎么样子的?以前曾被同事缠问过类似的问题。遇到这种宏大而又不着边际的问题,我的回复往往是“你还太嫩,现在我告诉你还是会忘掉的,等你干上个两年,不用我说你就知道了”。我边敲着键盘,边佩服自己的聪明才智。 两年后…… 这个小伙子长大了,并且坚定地又问了同样的问题。 我一愣神,脑海中不停浮现出一个声音“出来混,迟早是要还的”。想想也罢,是时候该把压箱底儿的货拿出来了,毕竟自封了“半吊子系统工程师”的title(虽然我自封的title还有很多:半吊子客服、半吊子产品经理、半吊子研发项目经理等等),不给你们露两手看看看来还真不行…… 概览 deepin系统启动,从整体上看主要分为了硬件上电、内核引导、内核启动、系统初始化、图形界面等几个阶段。如果将这几个阶段分为两个部分,那么第一部分的硬件上电、内核引导、内核启动主要是“引导(boot)”,更偏向让内核可以启动;而第二部分的系统初始化、图形界面两个阶段主要的任务则是“初始化(initialize)”了,因为对于一个系统来说仅仅有内核跑起来是不行的,还要有各种各样的服务对系统的软硬件进行管理,这也是平常大家说发行版跟纯粹的GNU/Linux内核不是一个概念的原因之一。 下面我从一个软件开发者的角度说一下我对每个阶段的理解以及一些调试的方法。 硬件上电 既然说了是软件开发者的角度,这个部分对我来说基本上相当于黑盒子了。但是大体上我们仍然知道这个部分主要是: 硬件上电 BIOS/UEFI bootloader 当你按下电源的那一刻起,电流就会“滋滋滋”的流向主板,启动BIOS(Basic Input Output System)系统。BIOS系统,顾名思义就是最直接跟硬件打交道的系统,因为有标准规定,所以输入输出设备的基本功能都是可以使用的,一些硬件的开关配置也可以在BIOS中进行操作。除此之外,BIOS还有两个重要的功能,一个是硬件自检;另外一个是加载引导。硬件自检这个跟作为一个”半吊子系统工程师“没什么关系,自不多说。加载引导的过程其实就是大家耳熟能详的MBR、小蝌蚪找妈…哦不…MBR中找bootloader了。 跟BIOS对应的UEFI,要说它们之间的区别,除了加载引导的方式不大一样以外。对我来说可能就是界面能够用鼠标点点点了吧,嗯……哈哈哈。 这里讲个段子,之前15.7搞启动时间优化的时候,测试的同学测试系统启动时间的优化情况,老是说效果不理想,我去看看吧,原来是他们测试系统启动是从硬件启动算起的,我说你们直接从内核引导开始计算,他还问我为什么。优化时间/(BIOS时间+GRUB时间+内核时间+图形时间) 跟 优化时间/(内核时间+图形时间)哪个大哪个小?我只能说这个测试同学的数学不大好……😂 内核引导 BIOS在MBR中(或者UEFI在主板专有的存储设备中)找到bootloader并加载后,bootloader就会开始加载Linux内核并启动了。 GRUB引导 deepin系统默认的bootloader是GRUB(GRand Unified Bootloader)。其实我一直觉得这个名字挺恶心的,大神们果然都是重口味……GRUB并不需要按照什么规则去硬盘中找系统,而是根据/boot/grub/grub.cfg中的启动项加载内核、启动系统,而这个配置文件则是在系统安装或者手动执行update-grub这个命令的时候生成和更新。 update-grub这个命令其实是对grub-mkconfig的一个包装,在非Debian系的发行版上是没有的。grub-mkconfig会执行的动作主要是: 加载/etc/default/grub中的一些配置项。比如GRUB_CMDLINE_LINUX_DEFAULT配置项会控制Linux的boot param。 挨个执行/etc/grub.d/目录中的脚本,用来生成最终的grub.cfg文件。比如我们平常看到update-grub命令执行时输出的哪些启动项,其实就是/etc/grub.d/03_os-prober这个脚本里面执行os-prober这个工具产生的。 在GRUB界面选择启动项,按e编辑启动项。除了普通的上下左右键移动光标,还可以使用基本的Emacs快捷键: Ctrl+N 下一行 Ctrl+P 上一行 Ctrl+B 左移一个字符 Ctrl+F 右移一个字符 Ctrl+A 移动光标到行首 Ctrl+E 移动光标到行尾 编辑完成后按Ctrl+X按照编辑后的结果启动系统,但是编辑的结果不会保存,也就是说如果需要永久修改某个启动项,就要修改grub.cfg文件或者会影响grub.cfg生成的/etc/default/grub以及/etc/grub.d/中的脚本文件了。 对于GRUB,我们一般需要知道的就这么多,关于GRUB其他一些用法和知识,可以参考GRUB与系统引导这篇文章。 UEFI直接引导 在UEFI模式下,除了使用GRUB来引导内核以外,还可以通过UEFI直接引导内核(需要内核开启了EFI Stub支持),具体的配置方式见Debian Wiki EFI Stub。需要注意的一点是在使用efibootmgr创建启动项的时候,可能需要-d参数指定设备,否则可能会导致创建启动项失败。 内核启动 内核启动部分其实主要是想说initrd。 initrd是一个小型的rootfs,这个rootfs保证了内核启动过程中所需要的内核模块和用户态工具。同时,它还需要为下一个阶段“系统初始化”做准备,也就是为init程序准备好真正的文件系统,并且启动init程序。 内核使用initrd启动的过程主要是: 执行init脚本(这个不是上面说得init程序,而是生成好的initramfs中的/init这个文件。后面的步骤其实都发生在这个脚本的执行过程中); 解析内核启动参数,识别关键的如debug、boot、break等; 执行/scripts/init-top/中的脚本; 加载内核模块; 执行/scripts/init-premount/中的脚本; 执行/scripts/$BOOT脚本中的mountroot函数,其中的$BOOT参数就是第2步中识别到的boot参数指定的,自带的可选项有local(本地启动,默认)、nfs(比如PXE启动); 执行/scripts/init-bottom/中的脚本; 执行init程序。 live系统 上面第6步提到initramfs-tools包自带有两种boot类型:local和nfs,我们使用live系统的时候的boot类型其实live。这个boot类型主要是live-boot这个包支撑起来的。 Read On →

深度数据盘和FUSE文件系统

说起FUSE,大概很早之前就知道了,但是写文件系统这种东西,大概一辈子也没几次机会会用到,所以当时也没怎么研究,直到最近遇到一个“扭曲”的需求…… 这个需求是这样的。在深度系统的安装器中,有一个全盘安装的功能,这个功能看起来非常简单:扔一块全新的或者老旧的硬盘给安装器,只需一杯咖啡的功夫,你的系统也就能优雅地躺在你的硬盘上了。然而,其中有一个处心积虑,哦不,深思熟虑的细节设定,就是假如你硬盘够大,安装器就会给你多分出一个分区:数据盘。 据说数据盘的主要作用是让用户存放数据文件,也就是以前用Windows的时候D盘或者E盘等的作用,放点图片、下点片之类的。用户重装系统的时候,也可以方便的做数据迁移。不过鉴于之前我们的一些客户对文件权限的设计不太理解,经常莫名其妙就出权限文件,所以,这个数据盘大概隐含了两个隐性需求: 文件权限不要太严格; 文件权限不要太严格…… 第一次尝试 收到需求的你肯定想,Linux(类Unix)把用户权限、文件权限划分地这么好,虽然也不算天衣无缝吧,但是也是大神们深思熟虑的成果,退回到上古时代的没有文件权限这种事,简直就是历史的倒退么……然而作为一名优秀的程序员,怎么能不理解这种为了用户使用方便,宁愿自己背负骂名的行为呢,所以我们毅然选择了不抵抗政策。另外,为了这个盘可以被双系统的Windows读到,当时我们很自然就选择了NTFS作为数据盘的分区格式。 然而,过了一段时间。 社区用户:我的硬盘发热好厉害呀,是不是这个NTFS分区…… 商业伙伴:这个NTFS文件系统的有点不清真啊…… 这显然没有达到我们预期的目的嘛,必须想办法搞定啊。数据盘这个需求就开始了它的扭曲之旅。 第二次尝试 如果不使用NTFS,那就在ext4上面做文章咯?在网络上搜索了半天,也没有发现什么好的方式,要么就是chmod -R xxx 这种,要么就是 chown……操作系统跟用户那可是一辈子的事情,这几种显然只适合做一锤子买卖的方式显然是不适合的。然后,我突然想到之前同事提到过的ACL(限于篇幅和主题,就不展开了),就研究了一下,果然还就能解决问题,两条命令: $ setfacl -d -m "g:sudo:rwx" /xxx $ setfacl -m "g:sudo:rwx" /xxx 其中的/xxx就是数据盘的挂载点,第一行命令设定挂载点文件夹的默认ACL规则为:所有sudo组的用户可以对文件夹有rwx操作权限,第二句设定挂载点文件夹的ACL规则为:所有sudo组的用户可以对文件夹有rwx操作权限。这两句话看起来好像没有什么区别,其实不同的地方在于第一行命令设定的是文件夹的默认ACL规则,而第二行命令设定的是文件夹本身的ACL规则。设定了默认规则以后文件夹里面新创建的文件或者文件夹就会继承这个规则,如果只设置文件夹的ACL规则,则新文件和子文件夹不会继承这些ACL规则;如果只设置文件夹的默认ACL规则,而不设置文件夹本身的ACL规则,则文件夹本身没有ACL规则生效。 虽然这个设定感觉有点让人发晕,但是好歹功能都实现了呀,一切都看似那么美好。 然而程序员的所有美好都怕测试这种物种,测试有一天突然发现:“咦?系统里面的A用户放在数据盘里面的文件怎么B用户无法访问?”程序员就多了个BUG…… 经过调试,发现一种神奇的现象:Linux(可能其他系统也是)对ACL的处理有点奇怪,假如在拥有ACL规则的对象(文件或者文件夹)上进行chmod操作,那么chmod 会对对象的ACL规则造成影响,影响的结果就是对象虽然有ACL规则,但是ACL的有效值会变成chmod要达成的效果。举个例子,假如文件原来的ACL规则如下: $ getfacl testacl # file: testacl # owner: hualet # group: hualet user::rw- group::r-- group:sudo:rwx mask::rwx other::r-- 文件的权限是644,但是sudo组的用户有rwx权限。这时候如果我们使用chmod 700 testacl修改一下文件的权限,再次查看文件的ACL会变成: $ getfacl testacl # file: testacl # owner: hualet # group: hualet user::rwx group::r-- #effective:--- group:sudo:rwx #effective:--- mask::--- other::--- 可以看到,group和group:sudo后面的有效值是---,即rwx权限全无,other也从原来的r--变成了---。 Read On →

《走向共和》观后感

​ 断断续续地从2018年下半年开始看《走向共和》,到今天算是看完了。 ​ 最开始知道这部电视剧,还是看到网友Tualatrix在Twitter上的推荐,不过当时看电视封面中最大头像的是孙中山,不太感冒,所以就没有怎么好好看,一般都是边玩游戏边看,但是看了几集以后顿时觉得过瘾,一共58集的电视剧把中国从甲午中日战争到护国、护法运动的历史算是做了非常精彩的演绎,而且电视剧的布景正是我喜欢的类似《大明王朝1566》(后来才知道原来是同一个导演张黎)、《乔家大院》、《大染坊》、《六龙飞天》那种朴素而又显得真实的布景,再加上对剧中主角的性格塑造非常细致,基本上推翻了以前从教科书中得到的对几个主角的评价,愈发觉得着实的喜欢。 主角们 ​ 因为剧情比较宏大,所以总共算是有四个主角,按照清政府倒台作为中间线,前半段主要是李鸿章主角、后半段主要是袁世凯主角,慈禧和孙中山贯穿其中,只是作为两段历史的领袖人物,慈禧要比孙中山戏份多得多,对剧情也重要的多(个人观点)。 李鸿章 ​ 这部剧之所以吸引我,大概就是前期对李鸿章的塑造大大刷新了我对他的认识,这哪是什么教科书中的卖国贼,片中的李鸿章分明是一个讲求实干、精于世故、老成谋国的人,苦苦支撑国事的偏于正面的形象: 为北洋水师的军费与朝中以翁同龢为代表的清流派争斗; 顾全大局(争取本来敌视他的南洋大臣张之洞,这点感觉比他的老师曾国藩对待左宗棠有手段); 有点跋扈,但是也对自己认清的现实非常坚持,视满朝的非议诋毁如过耳云烟; 马关和谈时尽其所能与日本人周旋(甚至把自己在日本被刺当作谈判筹码,与伊藤博文讨价还价,苦苦哀求砍掉2000万作为回国的盘缠,真是叫人揪心……); 对政局了若指掌,戊戌变法时跑到欧洲考察,实际是为了躲避帝后之争; 辛丑和谈的时候表现出的老道; 签订辛丑条约时与列强的周旋(李鸿章拦住了一起主持议和的庆亲王,而只签上了自己的名字。说:王爷还年轻,这种要背千古骂名的事还是由我这老朽担当了吧)。 ​ 李鸿章在政治上是一个高级玩家,狡猾地如狐狸一般,但是作为一个士大夫,还是表现出了那种家国天下的情怀,终然洞穿官场一切的潜规则,还是尽自己最大的努力来维持局面。作为晚清洋务运动的领导者之一,他可以说是举步维艰,但是仍然知难而上,运用自己的政治智慧沉着应对每个难关。 金句 “身怀利器,杀心自起,慎而重之!” “一代人只能做一代人的事情。” 评价 ​ 李鸿章作为一个天才,只能说生错了国家、生错了时代,为国苦苦经营,最后却落得个卖国贼的名分。 ​ 用剧中伊藤博文的原话来说:“伊藤不才,然何其幸哉,能驻足日本之地,此乃立宪国之地,且举国人才辈出;李鸿章大才,然何其不幸,为政于中国之地,其乃绝对专制之地,故而有才化无才,且举国人才,一遇专制俱为奴才。” 袁世凯 ​ 我记得以前我的一位历史老师曾经讲过一个笑话:“袁世凯一生只做过一件好事,就是他死了”,当时全班大笑,因为在小时候的电视剧里面,真没有看到过哪个剧里面有袁世凯,但是是一个正面形象的,坏人死了的才是喜剧嘛。 ​ 但是这部剧里面的袁世凯,太复杂,根本无法单一评价,正面看: 实干家; 勇武果断; 聪明; 能力出众; 讲义气(对小站练兵的弟兄、对英子); …… ​ 从反面看: 反叛者; 依附权贵; 阴险狡诈(杀了赵秉钧); 破坏共和; …… ​ 从一个成年人的视角,可能他做得很多事情,都对得起最后那句“我们这辈子,没有白活啊。”但是,作为一个统治者,为了自己的权利欲望去玩弄国家政体,确实只能说是历史的罪人…… 金句 “这就是政治,可以犯罪,但不可以犯错。” “这做事也罢,当官儿也罢,千万不能搞一锤子的买卖,不能过河就拆桥,你得老想着还有下一次,只要还有能力就要架桥铺路,不然那就是短视,做人没出息,办事也总是失败。” 评价 ​ 从我个人来说,我还是挺佩服他的,实干家又懂得政治规则,从一个痞子最终混成了帝国的皇帝,不可以说他没有才干。但最终,一招不慎,满盘皆输,明明什么都看得透彻,但是就是抵不住自己对权力的欲望,落得个众矢之的的下场。 ​ 用孙中山对他的评价,原话忘了,大意是“袁世凯本质上就是一个攀附权贵的人,先是李鸿章,接着是荣禄和张之洞,还有最后的庆王爷,他迟早是要当皇帝的,这是他的心病。只是仙子啊满世界都在搞宪政、搞共和,袁世凯非要当皇帝,这历史的潮流是不允许的。“ Read On →

WPS中的字体名

今天又被 fontconfig 坑到了……仔细想想,半年到一年前我还对 fontconfig 狗屁不通呢,而现在我已经被 fontconfit 坑了有几次了,这印证了一个真理:“只要你足够迟钝,世界就是美好的,一旦你有了某种能力,麻烦就会找到你”——这只是个玩笑,事实上不管你有没有能力,现实都不会让你好过 😈 在这些坑里面,有两个是跟今天主题相关的,也就是关于WPS中字体名称的两个问题: WPS 字体列表中中文字体在中文环境下不显示中文名(比如系统里面有宋体,列表里面显示 SimSun); WPS 设置段落字体(中文字体)后,工具栏显示的字体为英文名(比如你设置一段文字是宋体,但是标题栏显示的仍然是SimSun) 这两个问题有点像,但是却不是同一个问题(也不只是WPS有问题,而是WPS对字体的需求比较多): 第一个问题原先是 论坛用户报告 的(实际上刘老大也报过,不过被自动忽略了😂),论坛用户又报过来以后,大家看用户的报告太详细了,感动得一塌糊涂,顿时解决问题的动力都有了。我也折腾了大半天,不过脑袋里面一直有一个同事的声音:那是字体有问题!我也挺赞同的:盗版的字体,不靠谱很正常……所以,我就考虑能不能给字体做一些别名啥的,比如 SimSun 就叫 宋体……当然了最后就是玩了一下 fontconfig 的配置以后,默默就放弃了。 最后经过 @felixonmars 同学的排查,发现是上游的一个 bug ,而且已经修复,所以赶紧更了一波,解决了这个问题。 本以为皆大欢喜了,今天又有客户报过来 bug,说 Windows 上写好的文档,调整好的字体,跑到deepin下字体就不对了,废了老大的劲儿才又调好,其中就提到了选择方正字库里面的字体,显示的不是中文字体名称的问题。 怎么说呢,幸亏我脑子不好,不记得之前已经解决过中文字体名显示为英文的问题,要不然得跟客户和老板掰扯一会儿,我只记得字体的中英文名字好像是有点问题,所以默默赶紧去看了一下,还真真的有问题。 因为 DDE 并没有设置过多的 fontconfig 配置,所以我相信这不是 DDE 的问题,但是又觉得对于一个文字处理软件来说,如果这么重要的功能都有 BUG,我真不信 WPS 的人还能坐得住,所以就想试一下在 Ubuntu 下 WPS 的这个行为是否正确。刚好年前 ElementryOS 发新版的时候尝鲜装了一个在测试机器上,所以很快切进去下了一个 WPS 安装上,从一个正版的网站上下载了一个盗版的宋体,试了一下,果然踏马的是好的…… 理性的我用事实证明了感性的我是错误的,气氛一度很尴尬。 更让人尴尬的是,我也不知道这是怎么回事。但是,无巧不成书,就在这种尴尬氛围的笼罩下,我鬼使神差地在 ElementryOS (太长了,下面简称 EOS )上运行了 fc-match 宋体 这个命令,而且很神奇的发现输出的 simsun.ttf: "宋体" "Regular" 跟 deepin 下同样命令输出的 simsun.ttf: "SimSun" "Regular" 不太一样,这可把我乐坏了——要知道一个稍微复杂点的图形软件,打开 fontconfig 的调试以后,输出就是很可怕的,更别说 WPS!别问我是怎么知道的,回忆起来都是泪。但是现在使用 fc-match 就能重现的问题(我打心底认为这俩是同一个问题),调试起来就比较简单了。 Read On →

2018 年终总结

2018 年也不知道为啥过得这么快,似乎“嗖”的一下就过完了,但是仔细回想一下,还是有不少事、不少感想值得留存的,所以赶紧用文字记录下,不然以我的健忘性格,不用到明年的今天,我就不会再记得 2018 年我做了什么、经历了什么和有什么感悟了。惨痛的教训比如 2017, 没有总结,我看了 2016年终总结 甚至不知道我的 2017 相比 2016 是否有进步、有没有按照规划去做了对的事情。所以在这个时间点,就算是年终刚好出去参加同学的婚礼了,也在火车上抽了时间做了脑图,整理了一年下来的总结。 读书 总的来说18年读的书不算多,甚至可以用少来形容,不过总归还有些感悟,记录下来权做以后翻看旧书需要的介绍了。 《南渡北归》 拖拖拉拉终于几乎看完了全本,只是到国民党退到台湾以后,顿时有一种很丧的气氛在里面(不知道是书还是当时看的我),所以后面基本上就没怎么看了。 对于整本书的评价还是很高的,革命/战乱的年代,杂糅这知识分子的热忱、浪漫、坚毅、吃苦耐劳,沉入其中,感受每个人面对的挣扎和选择,对于一个人对人生和价值观的思考还是非常有促进作用的。 像《老残游记》和《浮生六记》一样,如果有机会,我还会再读几遍。 《技术管理之巅》 技术管理书,因为很贴近实际,所以显得比较接地气。 在看这本书的过程中想通了技术和管理其实是可以很好融合在一起,而不是互相对立的。 《把生命浪费在美好的事物上》 原以为是类似汪曾祺的哪些小散文的书,但是完全被吴晓波起的书字给骗了。把生命浪费在美好的事物上,你得先跟吴晓波一样有钱 :P 同上本书,这本书让我知道了“铜臭气”和“书呆子气”可以同时存在于一个人身上,并且很好地共存。 《曾国藩的正面与侧面》 青春期的时候,可能是热血漫画看多了,我总是喜欢认为自己是个“天才”,但是随着年龄增长,我越往后越发现我对于“天才”和“聪明”的需求越来越弱,反而是对“勤”和“恒”的需求越来越多。这本书并没有教会我做什么,而是加深了我早已有的很多想法,让我更知道如何为人和处事。 《原则》 忘记这本书是什么时候引起风潮的,似乎一时间所有的人都在看这本书。不过我还是因为懒没有看。等过了一段时间有次在火车上没事干,想找一本书看看就选择了这本书。 初看还是很有同感的,尤其是生活部分(其实就像作者说得,前面哪些他个人的经历,其实没有什么特别有意思的地方)的一些原则,我当时甚至想给深度的开发同事也弄一个 深度开发者行事原则 的,但是碍于这个东西实在不好讲,因为每个人本身的认知程度千差万别,想一下子拉齐到同一水平很不现实,所以一拖两拖,就废掉了。 不过我还是因此养成了一个把我在一些特殊时刻想到的一些感受和想法记录下来沉淀的习惯,收获也算不少吧。 《白夜行》 纯娱乐,读得相当快,好像是一两周之内读完的(这已经是我读书的最快水准)。读这本书是因为偶然一次机会在一个便利店看到一个《解忧杂货店》的舞台剧广告,上面写着“日本作家东野圭吾作品”,当时我就傻眼了——《解忧杂货店》不是村上春树的作品么???再三确认以后,我决定再读一本东野圭吾的作品,以示歉意,所以就选了《白夜行》。 书中的故事相当粗暴,但是很吸引人,就是那种“我已经猜到答案了,你快点告诉我是不是这样”一路走下去的感觉。 《见识》 吴军老师的书,都是干货的方法论合集。 按道理说一般说外企大佬写得书,多半是鸡汤(至少我认为是这样),但是吴军老师的书里面还是有很多大智慧。 《我们台湾这些年 I》(未完) 纯好奇,看着作者从小往大介绍,思绪慢慢从我的童年飘到现在,找回不少记忆。不过越往后看,越想借用《南渡北归》中蒋介石的一句话来送给自己和其他心心念互联网自由的人:“汝辈竟无革命精神若此!” 《奈飞文化手册》 得到APP里面买的,介绍奈飞公司文化的一本书,其实给我的感觉是跟《原则》这本书交相呼应的,书里面介绍的几个价值核心:“我们只招成年人”、“要让每个人都理解公司业务”、“绝对坦诚”、“只有事实才能捍卫观点”要么是有很多共鸣——比如“要让每个人理解公司业务”,我一直觉得公司很多东西该透明要积极去透明,也一直在努力让开发部内部所有的事情都清晰透明;要么就是对我启发比较大——比如“我们只招成年人”。其他章节不是不好,而是因为需要在公司更高层面去运作,所以我的认识相对较少。 旅行 全年两次旅游,一次在宜昌,一次在云南。 宜昌算是散心之旅,我和小崔两个人,游记见摆脱尘世繁杂——宜昌休闲4天游。 云南真的是一场说走就走的旅行,因为今年公司没有组织年度旅游,所以云南游算是全年的大游了,但是其实只是一时冲动陪朋友去云南探亲,结果他的探亲成假,我们旅游去成真了。无游记。 电视剧&纪录片 电影就不说了,跟着小崔看了好多电影。只说下对我印象还比较深刻的电视剧和纪录片。 《我们这一天》 家庭剧,这部剧让我对未来的家庭充满期待,也很感恩我后来不再是独生子女。 Read On →

深度滚动更新工作流程

背景 以前的系统发布模式为平均每3个月一次系统发布——开发周期2个月,测试周期1个月。这虽然保证了每次系统发布的状态都比较稳定,但是仍然避免不了在大量用户在不同场景下产生而发现新 BUG 的局面,而且因为这种发布模式缺少快速更新的机制,导致很多在内部已经得到修复的问题无法及时推送到外网,用户在这段时间内只能忍受一些 BUG 的干扰。所以,我们在 15.6 和 15.7 的时候引入了”发布后一个月“的概念,在这个时间段内,开发主要做问题修复工作,修复的内容可以快速推送到外网,而不用经过繁杂的测试,期望快速解决用户在使用新版本中遇到的问题,这就是深度滚动更新的原型。 15.8开发的过程中,我们又思考了一下这个过程,刚巧我们决定了要尝试”开放和透明“、拥抱社区,所以觉得目前这种把”大教堂“和”集市“两种开发模式揉在一起的方式不是特别明朗,对系统发布者和开发者都是一种负担,所以”从善如流“——从 15.9 开始,deepin 系统的发布开始遵循滚动更新的模式。 滚动更新流程 深度的滚动更新,需要参与系统发布的产品、开发和测试共同合作,所以制定了一套简单的工作流程作为大家协作的基础,从粗到细主要分为了以下几个范围: 1. 系统版本 系统版本的概念跟以前的 15.7、15.8 等没有不同,都会提前指定这 2 - 3 个月的一个工作计划,在阶段性工作完成之后,会有新版本的 ISO 发布。与之前不同的是,新功能不是等系统发布的时候一次性放出,而是在每周开发内容完成、测试通过以后就会放出;另外一个不同是,系统发布不再以完成所有开发内容为前提,而是在系统版本计划的时间点达到以后即发布,未完成的内容放入下个版本工作内容中。 工具使用: 系统版本规划的内容会展示在官网的“版本规划”中进行展示; 需求文档会邮件通知所有参与系统发布的同事。 2. 里程碑 由于前面所说的新版本不会要求计划内容都完成才发布,所以为了防止工作计划与实际工作产出相差过大,所以将每次系统版本发布做了阶段划分,也就是里程碑。举个例子来说,15.9 开发的阶段会划分为 15.8.1、15.8.2、 15.8.3、 15.8.4 等。 在每次里程碑开始之前,产品需要提前细化里程碑内的需求,在里程碑开始之前还未明确的需求,会被放入下个里程碑中。同样,在这个阶段,测试会根据产品需求编写测试用例。需求和测试用例都会经过一次评审。每个里程碑到达预定时间点之后,未完成的工作内容会按照优先级放入下个里程碑或者延后处理、放到其他里程碑中。 工具使用: 里程碑使用 github issues 中的 Milestone 工具来进行管理; 细化的需求文档以及需求变更会邮件通知所有参与系统发布的同事。 3. 工作周 每个里程碑由两个工作周组成。在每个工作周内,开发需要完成计划中的开发内容和上个工作周测试问题的修复工作,在每周结束的时候,开发对稳定的项目打 tag,并提交到 crp 平台进行打包、提供 changelog 供产品和测试在下个工作周进行验收。同样,在每个工作周内,产品和测试需要完成对上周开发内容的验收工作,保证在周三前完成功能验收、功能测试和 BUG 修复,周四时发布更新。 工具使用: 系统各个组件包版本控制、changlog 使用 crp 进行管理; 每周更新内容在 internal-discussion 中建相应里程碑发布任务的 issue 进行说明; 社区官网提供每次更新的更新注记。 目标 目前对滚动更新的期望主要有以下几点: Read On →

修理 FreeRDP

起因 头段时间入了一个大坑儿,大概被坑了有一个月之久,出来之后同事还不忘嘲讽一番:”这么个事情就搞了一个月,看吧,你果然是老了“。听了这句话,心里真是百般滋味,但转念一想,”我年轻的时候做事好像也不怎么快“,顿时也就释怀了 :) 这个坑就是”给 FreeRDP 的 RAIL 模式添加托盘支持“,当然,跟所有的需求一样,这么具有总结性而又直指根源的需求描述,绝对不是它最原始的模样——我刚接到这个坑的时候,它是这样的:FreeRDP 的 RAIL 模式下,应用的托盘在我们 DDE 下不显示。请注意这里说得是不显示,而不是后来发现的压根儿没有支持! FreeRDP 说到这,可能有读者还不了解 FreeRDP 和 RAIL,所以先简单介绍一下。 RDP 其实是一个协议名称,全称 Remote Desktop Protocol(远程桌面协议),是微软公司开发的一套用于远程桌面展示和操作的协议,FreeRDP 就是它在开源世界的实现咯。而 RAIL 的全称是 Remote Application Integrated Locally (远程应用本地集成),其实就是非常类似大家熟悉的虚拟机的”无缝模式“,通过将应用的显示跟本地环境相融合,让用户完全感受不到这个应用其实不在本机运行——就是这么一种技术。 问题也就出在这,我当时第一反应是这么老的技术实现肯定比较完整了,托盘没有显示出来应该是跟 DDE 的兼容性有点小问题,稍微修一下就完了,三下五除二的事情,所以满口答应了下来…… 经过 既然答应了,硬着头皮也要顶下去的。何况调 BUG 这种事情——不管是不是我们自己的问题——在深度都是家常便饭。慢慢地,调各种项目的 BUG 竟然成了我的一种乐趣——每次开始接手一个新的项目的时候,我都把自己当成了福尔摩斯或者胡八一,或者也可以是其他全世界最聪明的那类人 😜,在通过代码找寻问题线索的过程中,慢慢成为这个项目世界中的主宰,解开真相…… 额……不好意思,白日梦又发作了一会儿。总之,这次也不例外,而且刚好这次在调问题的过程中有记录几个关键环节,所以打算把中间的过程写成日记性质的记录,看看能不能有更好的阅读效果: 2018-11-14 从”沈老板“那收到需求,说 FreeRDP 在我们系统上有问题,应用的托盘显示不出来,QQ之类的程序关闭了窗口以后就没办法显示出来了,无法使用。这丫的又拿刘老大来压我……呵呵,想削他。不过看在他快要当爸爸的份上,还是算了。问了下时间要求,大概需要两周左右有初步的结果。不过我自己最近没有什么时间,先把锅丢给了印象中还比较熟悉网络协议的 @Blumia 同学。 2018-11-15 从 @Blumia 那收到反馈,可能 FreeRDP 没有实现托盘图标这部分的功能,我怕他一个人搞不定,简单翻了翻 FreeRDP 的项目 wiki 和 RDP 的一些介绍,给了他,让他先帮忙找一下需要补充实现部分的代码结构。 2018-11-16 没时间处理。 @Blumia 搭了测试环境。 中间几天两个人都没有时间处理 FreeRDP 的事情。 2018-11-22 留了少部分时间,看了 FreeRDP 的代码,大概找到了托盘图标相关处理应该在的位置。 Read On →

15.8研发心得

不早也不晚,2018年11月15日 deepin 15.8 如期发布。这虽然是个好消息,但是没有了延期的梗,我竟然不知道这篇研发心得应该如何开头……😓 开头这件事情总是很难,因为要做到一些以前没有做到的事情,就要求能将自己的水平提高哪怕那么一点点;同时,开头也不宜于高调,高调的开头太容易造成虎头蛇尾以致不能坚持的局面。在我的价值观里,与其浪费时间和精力在不能坚持的事情上,还不如什么都不做。所以很多事情我都不愿意开头,就像写这篇研发心得一样。 不过,幸运的是我们对发布系统这件事情倒是充满着热情,以至于我们能在每一次系统发布的“轮回”里,都无所畏惧地开头并且坚持如一。比如 15.4 的毛玻璃效果、15.5 的高分屏、15.6 的应用深色主题、15.7的性能优化等等等等……当然,这次的主角 15.8 也不输从前。 新特性介绍 15.8 中新的变动着实不少,但是从一个研发的角度来看,我觉得最重要的变化应该是组织系统开发和发布的人发生了变化。之所以说这个比较重要,是因为 deepin 的前辈们把接力棒交到我这里,我终于可以把它顺利地转交到合适的人手中了,这句话的言外之意是什么呢?就是大家以后如果遇到什么 bug,进门左转找 @zccrs 😂。 说明了以上信息,就可放心地介绍这次的新功能了。不过说实话,这次的新功能都相当直观,用不着我费什么口舌,再加上本次研发心得的重点不在此,所以大部分的新功能请看 系统发布新闻,这里只说两个我最喜欢的点吧。 第一个要说的,是15.8 的新功能里面最让人惊喜的 Dock时尚模式 的托盘插件 的设计调整: 为什么呢?这主要是因为以我的聪明才智,都一直认为时尚模式的托盘是一个无解的问题:系统托盘占用大量空间,应用托盘使用不方便……除非引入类似 macOS 的 topbar (估计很多人也是这么想的,所以都默默地在商店里面安装了 deepin-topbar吧)。事实上,当时我们讨论解决方案的时候也是差不多一样的状态,每个人都欲言又止,显然是还没说出口的方案就被自己推翻了,然而就在这个时候,设计师默默地上了一副设计图,把所有的应用托盘也放大成了与应用图标无异的大小。 我:!?!?!?(黑人脸 我刚要扔臭鸡蛋,设计师咔嚓又上传了一张图,仿佛在说 “蛋下留人~” 而转机就这样发生了,我看到设计图,就如大家在15.8看到的Dock时尚模式一样,托盘问题竟然被 almost 完美地解决了——在最后的关键时刻设计师保住了自己的颜面。 怎么说呢,这基本上是我在深度继看到一个开发同事用钥匙给电脑开机感到由衷地佩服以来,再一次罕见地(尤其是被设计师?😈)觉得世界观被刷新的一次体验了。 另外一个要提的是一个很小的点,不过现在想起来都会有一种吃了广告中的德芙的感觉——丝滑。是什么呢?如果你现在使用 deepin 浏览这篇文章,应该能看到我特地在文章开头、上一段和中间甩锅那一段,几乎到处都贴了 emoji 表情: 能正常显示,而不是豆腐块! 关键是它们是彩色的!!! 整篇文章不再有黑乎乎的表情——这简直是使用Linux写技术博客的 Blogger 的福音啊。如果你也想在文字编辑的时候输入开爱的 emoji 表情,可以打开 https://getemoji.com/ ,只需 copy&paste,瞬间让你拥有进入 21 世纪互联网的赶脚。 至于这个新特性为什么没有写到更新注记里面,是低调,是彩蛋,还是忘了写?咳咳,有点赶时间,继续往下写了 🙄🙄🙄 。 开放和透明 上面说了发系统的接力棒已经成功交(shuai)接(guo)给别人了,那我去干啥了呢?总得做点啥吧,要不被开了就不好玩儿了嘛😱。 我这段时间做得其实就是开放和透明。 在中国说起开源,应该没有人不知道深度作为“东半球最大的开源软件公司”的名头,如果有人不知道,那也让我们先姑且这么认为着 😜, 深度从出生的那一刻起就一直在开源——深度出品的软件产品中95%以上都是开源的,但是直到最近我才老有一种感觉就是深度一直在“开源”,但是并没有在“做开源”。 深度是很长于做产品的,每个产品都可以做得既小巧玲珑,又戳中用户痛点,所以积累了不少海内外用户。这些用户使用着我们的系统,时不时灵感来了还会提出一些宝贵的意见和建议,这本是极好的。但是作为开发者的我发现,其实这批用户里面有不少同行,他们也想为深度的开源事业做出自己的贡献,天天问我:How to contribute。我脑子飞速旋转,“这个功能貌似他可以加一下?不对,这个功能需要知道很多故事背景,说来话长……还是算了”,“那个bug他好像可以修一下,但是好像也不能按照常规的方式去修复……一两句话也说不清楚”。思来想去,最后只能以“你可以帮我们测试,测试也是一种贡献呀”、“你会德语呀,这么厉害,要不要帮我们加点翻译” 等等的回复搪塞过去,说完这些内疚到简直想出去哭一场。更有甚者,有些开发者克服了重重困难,终于提交了 CL (可以理解为补丁)想要一些功能,内部讨论半天给出一个决定和回复,对方回复,内部再讨论半天给一个回复……效率极低,还容易导致各种误解。更可惜的是,以后甚至还会有同样热心的开发者提交类似的补丁,然后重复前面的过程,及其浪费社会生产力。 Read On →

通过 Unix Domain Socket 传递文件描述符

Unix Domain Socket 是 Unix 系统下重要的本地进程间通信(IPC)机制之一,在 DDE、GNOME、KDE 等 Linux 桌面环境中常见的进程间通信方式 DBus 有一种实现方式就是基于 Unix Domain Socket 做的。虽然一直知道它的大名,也一直知道 Unix Domain Socket 可以用来传递文件描述符,但是碍于以前经验和眼界不足,加上没有深入去了解,完全不知道能传递文件描述符是多么强大的能力和必要性。 首先,我想着文件描述符不就是一个数字么,哪个 IPC 不能传递数字呢?完全没有思考到文件描述符是只在进程范围内有效,同样一个文件描述符放在不同的进程完全就不是一回事儿。这时候你肯定想,既然传递文件描述符这么麻烦,为啥非要传递文件描述符呢,使用文件名不也是一样的么?那么恭喜你,你也有更我一样在践行陶渊明老前辈看事物“不求甚解”的作风。传递文件描述符还是有它的必要性的,一方面,文件描述符代表的不只是一个文件,它还包含了文件打开的状态,比如 seek 的位置等,有点进程之于可执行程序的意思,拿到文件描述符也就拿到了这些动态的信息;另一方面,文件描述符不只对应于本地文件,它为了一众可读写对象提供了统一的读写接口,包含什么呢?本地文件、(匿名)管道、标准输入输出、甚至于 Socket 本身等……可以让你完全不关心文件描述符背后的实现是什么而方便实现自己的逻辑代码。 想通了以上道理,又有了以前似曾相识的感慨“古人诚不欺我”——前人留下的东西,必然有一定的合理性。这也是为什么我比较排斥看见一个软件不满意就立即重新造,尤其是能流传很广或者流程时间很长的软件,里面很多看起来不必要的东西,可能有其存在的合理性,最好的做法是尝试去改进,改进的过程了解其历史、学习其精髓,等自己胸有成竹的时候再下手重造不迟。额,跑题了…… 回到正题,之所以前段时间突然研究了一下 Socket 传递文件描述符的东西,是遇到这样一个需求:一个进程将自己的标准输入、标准输出和标准错误输出映射到另外一个进程相应的位置。带着对 Unix Domain Socket 的朦胧认识,写了一个简单的实现原型: // outlet.c #include <sys/socket.h> #include <sys/un.h> #include <string.h> #include <stdio.h> #include <errno.h> #include <unistd.h> #define SOCKET_NAME "/tmp/connection-uds-fd" int make_connection() { int fd; int connection_fd; int result; struct sockaddr_un sun; fd = socket(PF_UNIX, SOCK_STREAM, 0); sun.sun_family = AF_UNIX; strncpy(sun. Read On →

给 Doxygen 生成的文档中 Qt 的引用添加链接

额……这个标题怎么改读着都不怎么顺口,不过不用在意这些细节,问题不大 :) 上篇文章提到了 如何给DTK添加文档 ,给同事讲的时候有同事提出来最好能自动给对 Qt 的引用加上链接,我当时拍胸脯说文档里面 Qt 的类和方法随便引用,到时候一定让生成的文档可以链接到 Qt 的文档上。其实,到啥时候我也说不准……所以,还是研究了一下,翻了半天的 Stack Overflow 和 其他一些资料才搞清楚要怎么做到,这里记录一下。 如何在文档中添加外部文档的链接呢?官方文档 说得其实挺简单的: TAGFILES !最开始没有仔细看文档,理解歪了,以为 tags 文件是一个文档压缩包,添加到 TAGFILES 这项后面生成文档的时候自动下载,然后自动根据索引添加引用链接到文档中。所以,根据 doxygen generated documentation with auto-generated links to qt project 这篇文章,Doxyfile 配置文件写了: TAGFILES = qtcore.tags=http://doc.qt.io/qt-5/ \ qtgui.tags=http://doc.qt.io/qt-5/ \ qtwidgets.tags=http://doc.qt.io/qt-5/ \ qtxml.tags=http://doc.qt.io/qt-5/ \ qtnetwork.tags=http://doc.qt.io/qt-5/ 生成文档,怎么都不生效…… WTF ?! 继续 Google ,发现一个提交, 里面的 for i in core svg xmlpatterns; do curl -fsSLO "https://doc.qt.io/qt-5/qt$i.tags"; done; 引起了我的注意,恍然大悟: 原来这个 tags 文件就是索引文件,需要预先下载下来,之所以有 = 加上一个网址,是因为 tags 中只有类名到文档名的映射,并没有规定使用某种协议以及host。 Read On →