写点什么

清华大学莫一林:信息物理系统中的安全控制算法

  • 2020-10-12
  • 本文字数:9251 字

    阅读完需:约 30 分钟

清华大学莫一林:信息物理系统中的安全控制算法

中文讲的“安全”,其实基本上包含了英文中的两重含义,一个是 Safety,一个是 Security。信息物理系统中的安全问题主要是指 Security,也就是说,如果有人想要攻击你,在这种情况下,怎么能够保证系统的正常运行?

信息物理系统

“信息物理系统”,这个词大概是 2006 年由美国的 National Science Foundation(美国国家科学基金会)最开始提出来的。信息物理系统本质上来说是 Computation(计算)、Communication(通讯)、Control(控制)三 C 的融合,把三个 C 互相之间结合起来,嵌入到一个物理世界当中,从而能够使得整个系统更好地感知或者控制物理世界。


比如,无人驾驶就是一个信息物理系统,因为无人驾驶本身是有一个物理的实体,有很多传感器来收集数据,这些数据经过通讯上传到计算机或者云上面,同时车和车之间可能还有通讯,然后去做感知、去做导航,再反馈到无人车的执行单元,最后反馈到物理空间。这些过程既包括了计算,也包括了控制的一些问题。



其实,信息物理系统是一个很大的概念。之前大家说安全,其实更多的是想到计算机安全或者网络安全,现在更多的是手机这类智能设备的安全。但是,信息物理系统安全为什么现在被提上了议程?这其中主要的原因是传统的控制系统,比如汽车内部的通讯是通过 CANBUS 实现的,这样的通讯本质上来说是一个独立的、专用的网络,并不和其他网络产生任何的连接。所以在这种情况下,就很难去大规模地攻击这样一个系统。

信息物理系统的安全威胁

但是,现在智能化逐渐成为了一种趋势,而且智能化的一个核心的事情,就是要使用很多新兴的感知和网络的技术,实现万物互联。在这种背景下,就会产生非常多的问题,因为所有东西都联网了,那么系统受到攻击的可能性就放大了很多。在这种情况下,怎么保证整个系统的稳定性或者说维护系统正常运行,这是一个很大的挑战。



上图是我们之前说的智能家居的一个示意图。智能家居希望人们可以通过比如手机 App 去控制家里的电器,但是一旦家里的电器都上网之后,智能家居控制系统的安全就会变得非常重要,如果当一个攻击者可以操纵成千上万个家庭电器的话,这就可能带来非常严重的问题。


我们实验室从 2010 年前就开始做信息物理系统安全方面的研究。当时,有黑客设计了“震网病毒”,它的目标是伊朗用来提纯铀 235 的离心机。“震网病毒”破坏了伊朗上千台的离心机,最后对伊朗核计划造成了很大的损害。这也算是一个利用“信息战”成功带来破坏的一个例子。也是因为这个事情,让我们把信息物理系统的安全问题迅速提上了日程。

震网病毒

“震网病毒”的例子属于国家行为,可能比较少见,现在针对一般信息物理系统的攻击行为也越来越多。比如 2016 年,美国机构的报告就指出,全年一共有 290 多次针对美国工业控制系统的攻击,覆盖了制造业、通讯、能源等多个行业。



攻击有很多种类型,先说比较常见的。如果系统联网,可以通过网络去侵入系统;即使系统没有联网,那么还有一些方式方法,比如像“震网病毒”的例子,是通过 U 盘一层一层带进去的。这些方式都能造成很大的破坏。


我觉得比较值得关注的是第二个问题,一般做控制或者这种背景的研究人员,很多时候对计算机安全并不是特别有经验,那么开发的系统就可能会存在很多的漏洞。甚至有很多软件的开发者自己都不知道自己的系统有漏洞,但是黑客就可以发现你的漏洞。比如说像“震网病毒”的例子,伊朗不知道系统有问题,但黑客有内部资料,发现这个系统有问题,然后就利用这种漏洞去侵入了伊朗的系统。


大家比较担心的一个事情就是现在的系统变得越来越复杂,比如一辆车可能有几百个 ECU(Electronic Control Unit),一个波音 787 可能有上百万个零件,这上百万零件中的 70%都是外包出去的,而一级外包商可能再外包给二级、三级,最后整个供应链就变得很复杂,这相当于是全球生产,最后汇集到西雅图去装配。那么在这个过程中,怎么保证装到系统上的每一个零件都是安全的,这也是一个值得思考的问题。

黑客攻击汽车系统

其实,在传统的汽车信息物理系统当中,漏洞还是有很多的。比如 2015 年有一个比较著名的事件,有两个黑客(这两个人应该只是研究者,并不是真的想要搞破坏)通过攻击克莱斯勒吉普的一款车,入侵了这辆车的显示信息,就是所谓的 implementation,还包括一些娱乐系统,然后通过这个系统,进入车内部的网络来控制这个车,比如说方向、控制刹车,甚至包括安全气囊等等。


有人可能会说,像你们碰到这些问题,在计算机里面也都有,而且已经研究了很长时间了,为什么还要单独提这样一个概念,这个信息物理系统安全中到底有什么新的东西吗?我觉得这个核心价值在于:传统的研究主要都是在所谓的 Cyber Physical System。而信息物理系统,它的核心的是说那些有“物理”的系统,那么这个物理系统就带来了很多的挑战。


首先,从传统上来说,如果一个计算机受到攻击,最差的情况,也就是将这个计算机关闭就结束了。但是如果是一个高速行驶的车,无法将它直接关闭,只能让它缓慢地停下来,但是停下来这件事情本身因为有物理系统的参与,所以就不是一个简单的事情。而对于无人机来说,甚至都不能让它停下来,必须让它以一定的速度去飞,因为如果是固定翼无人机,停下来就可能意味着坠毁,所以在这个过程中,物理系统带来了很多的挑战。


另外一个问题是,我们不一定能够让物理系统停下来,比如说如果一个电网受到攻击,那么我们希望能够尽可能把被攻击的地方隔离出来,而不是要让整个地区比如北京市出现停电。这个意思就是说,在系统受到攻击的时候,要让这个系统还能带着“伤”去运行,而不是一旦有一点风吹草动就需要重启,这个也是一个很大的问题。最后,这些物理系统其实都需要非常高的可靠性,比如对飞机来说,我们之前跟波音做过一些项目,他们要求放上飞机的任何东西都需要经过鉴定,必须保证飞机有极高的可靠性,要远远高于杀毒软件要能检测出 99%病毒的这种可靠性。


很多传统的信息安全方法,都是一个所谓的 Best of Effort Approach,就是说,尽可能地提供能提供的最好的服务,但是并不能给出特别多的保证,因为对于一些需要非常高可靠性的系统,即便存在很小的可能也许就隐藏着一个很大的威胁。

为信息物理系统构建“护城河”

在信息物理系统里面,为了保证这个系统的安全,我们需要保证这个系统有非常高的可靠性。其实,任何一个单一的方法都是很难完成这个目标的,我们需要是一个多层的防御机制,它就像一个城堡一样,外面还有一个护城河,中间有一个城墙,里面还有一个城墙,必须要层层地设防,只有这样才能解决这个问题。



我觉得这其中有几个比较关键的点,比如 Prevention、 Detection、 Resiliency 、Recovery。其中,Prevention 就是怎么防止别人进来,那么这个地方可能是需要更好的防火墙,比如说杀毒软件等等这些东西。


当然,我们不可能百分之百地把别人都挡在系统之外,如果有人进来了之后,我们就需要去检测这个系统到底有没有被入侵,包括在一个大的系统怎么去定位哪几个部分被入侵了,这就是所谓的 Detection。另外,我们设计一个系统,需要考虑到一定的 Resiliency,比如说有一个汽车上面有一个零件坏了,这个系统就完蛋了,那么这个系统就不是很有韧性,所以系统能不能带“伤”运行,也是一个需要考虑的因素。最后,当发现这个系统出现问题之后,我们可能就会需要有一个所谓的恢复过程,比如重启等等手段。整体来说,我觉得要通过很多方面,通过多层防御来保证信息物理系统的安全。

信息物理系统中的安全控制算法

今天,我想给大家讲一讲我们在信息物理系统做的一些比较初步的工作,主要讲两个方面:一个是检测,一个是韧性。首先,从控制这个方式来说,怎么去思考信息物理系统安全性这个问题?当然,并不是说控制就能够彻底解决这个问题,还是需要一个多层的防御。

控制

控制,到底能给我们带来什么? 以离线设计系统为例,首先我们可以通过控制找到这个系统关键的部件,然后对这些部件做额外的冗余设计。在这个系统没有上线之前,我们可以对系统做一些可控、可观的分析,进而提升系统本身的韧性;上线之后,我们可以利用传统的方法如故障诊断,当然这里就变成了入侵诊断和入侵定位的问题。此外,我们还可以做一些鲁棒控制,保证系统的控制器在有攻击情况下依然能够容错。最后还有一个问题,一个大的系统想要让它更安全,我们到底应该先加固哪个地方?这都是控制可以提供给我们的一些东西。

检测

接下来,我主要讲一下关于检测的问题,我们也是受到“震网病毒”例子的启发之后开始做了相关的研究。“震网病毒”是 2010 年被发现的,从计算机的角度来说,它是一个很复杂的、很难防御的病毒。但是从控制角度来说,它的策略其实相当简单。离心机本身是一个类似于快速旋转东西,如果想要毁坏离心机,那就需要让它转的比原本设定的转速快很多,但是如果只是让它转的特别快的话,由于整个系统有传感器,传感器就会发现离心机转速太快,从而触发报警,报警之后就会有技术人员前来检查,整个过程并不能对这个系统造成很大破坏。


但是,“震网病毒”采取的一个策略是先不去攻击这个系统,而是在这个系统正常运行的时候,记录下它的传感器输出是什么情况(比如说离心机的转速)。为了很好地说明问题,我们假设离心机每秒 1000 转,“震网病毒”就记录了很多这样的数据。然后,当真正开始去攻击系统的时候,震网病毒就会把它记录的数据做一个重放,就是说把整个系统的转速调到比如 2000 转的时候,会使用之前正常的数据去替换异常数据,那么系统操作员看到依然是正常的转速,就不会察觉这个系统已经出现问题了。比如在一些警匪片中,匪徒会去把他们想要抢劫的地方的监控视频的影像做一个重放,比如用前一天没有异常的影像去覆盖掉抢劫的影像,跟“震网病毒”的策略很类似,在信息安全领域也是比较常见的“重放”攻击。



大家可以简单地看一下这个系统的框图,比如说我们做一个离心机或者一个其他的物理系统,需要做控制。那么我们使用传感器去监测这个系统,传感器的输出会给一个估计器,对于无人驾驶来说,可能这个应该叫感知,而不能简单地叫估计,因为它的功能可能会更复杂。但不管怎样的系统,我们都需要通过一个这样的东西,对收集到的信息做一个处理,然后得到系统的状态,再根据状态来设计系统的控制,最后反馈给物理系统。估计器可能还会输出一些信息传递到故障检测器里面,然后故障检测器会检测收到的信息 y(k)是不是有问题,大概就是这样的一个系统。



对于攻击来说,也分成了两个阶段,第一阶段攻击者先不去修改系统控制这一部分,只是被动的去记录一些传感器的信号。当记录足够多的传感器信号之后,进入第二阶段,开始去修改系统的控制信号,修改这个信号的同时,攻击者还要做的另外一件事,就是要把系统的传感器的这一边给断开,从而把传感器的真实数据替换成之前记录的正常数据。



由于系统本身是有故障检测器的,所以最原始的系统在设计的时候根本没有考虑安全性,没有考虑是否能检测出来所谓的“重放”攻击。事实上,“重放”攻击并不是总是有效的,我们发现有一些系统可以检测到“重放”攻击,而有一些系统是不能检测的。如上图所示,Y 轴表示检测器报警的概率,报警概率最大值是 1。整个系统的重放是在时刻零开始,那么作为第一个系统,也就是蓝线标记的系统,我们可以看到在重放开始的时候,它有一个比较短暂的损害过程,就是说这个时候报警的概率有一些,但是也不是特别高,然后很快报警概率就缩减到一个接近于 0 的值;而第二个系统,也就是红线标记的系统,我们发现它的报警概率随着“重放”变得越来越高,最后会趋向于 1。



但是,很多系统跟蓝线标记的系统一样,没有办法检测出“重放”攻击。那就可能会陷入一个问题,攻击者会背着系统的操作人员在系统里面做一些手脚。针对这种问题,我们设计了一种主动检测的方法。刚才所说的检测是被动的检测,通过收集很多的传感器的信息,然后去看传感器的信息是不是和这个系统本身模型是相符合的。但这个方法存在一个很大的问题,比如控制离心机,它的转速就一直是 1000 转,那么当传感器告诉我们转速是 1000 转时,事实上这个传感器从某种角度来说就没有给我们任何信息,因为系统控制的很好。


我们的想法是能否可以不把系统控制得这么好,我们主动在控制信号中加一个扰动信号,也可以叫做水印信号。这就是说水印信号是藏在真实的控制信号中的一个比较小的噪声。如果我们的系统没有受到攻击的话,那么这个噪声就会被传感器监测到,然后进入估计器,估计器能够在传感器输出的信号中识别这个噪声。当系统遭遇了“重放”攻击,因为系统的这个噪声是完全随机的,那么传感器里面的随机信号跟现在接收到的随机信号就对应不上,因为现在接受到的随机信号是之前的信号“重放”过来的。因此,我们可以通过添加一个这样小的扰动的方式去刺激这个系统,然后让这个系统对这个小的扰动产生一个响应,这样我们就可以去检测出这个系统到底有没有出问题了。我们称这种方式为主动检测方式,主动地去激励系统,而不是被动的去收集信息。其实,这个方法也跟计算机科学领域所说的 Challenge-Response 比较相似,通过给这个系统一个 Challenge,然后这个系统就要返回 Response,这样就能感知到整个系统、整个控制回路是不是都是完好无损的。



上图是我们做的一些实验的结果。针对的是一个非常简单的系统,大家可以认为这个是噪声的能力,我们发现随着加的能量越高,检测的概率会变得越高。我们大概的处理思路就是这样的,后面会有一些技术的问题,比如说加个扰动信号进去之后,系统的控制就没那么好,这产生代价会有多大?代价和检测性能之间会存在什么样的关系?其中的 Trade Off 到底应该怎么样去做权衡?我们可以把它看成一个类似于优化的问题,然后我们可以去做一个求解。



事实上,我们现在做的这些设计都是基于模型已知的,因为做系统控制通常来说大部分都是假设系统模型已知的。目前,基于数据的方式越来越流行了,我们也尝试去做了一些数据驱动的实验。其中我们需要作一些简单的假设,比如系统本身是稳定的,我们知道 x 到底有几维,其他具体的参数假设是未知的。然后我们可以去做一些数据驱动的方式。


想法也很简单,就是我们要在这个地方加一个随机信号,加了这个随机信号,这个系统会产生一些刺激,产生这些刺激之后,我们就可以通过输入和输出的关系来对系统内部的具体参数做一些推断。关于最好的信号具体应该怎么加?检测装置应该怎么去做?这些属于具体的细节,在这里我就不展开仔细讲了。下面是我们针对化工领域常用的 TEP 系统做的一个仿真。虚线是我们在没有模型知识的情况下,通过数据学习了水印信号和检测器的最优设计,得到的检测器的输出。


可以看到,跟有模型的实线吻合得非常好。另外,这个系统在 100 时刻收到了“重放”攻击,可以看到我们的水印方法可以有效地检测到攻击。


算法设计

下面我想讲的是一个有韧性的算法到底应该怎么去设计。这里讲的也是一个非常简单的问题,类似于一个简单的状态估计的问题。比如说自动驾驶的汽车里面有很多传感器都可以给这个车做定位,比如雷达、GPS、IMU、视觉传感器,那么我们应该怎么把这个东西给融合起来,这就是一个很传统的状态估计的问题。


这是一个非常简化模型,有很多传感器,每一个传感器都在测量一个叫做状态的东西,这个状态是记做 x,传感器的测量值记做 z。当然这里指的是一个简化的线性高斯模型,就是说测量值是真实状态的一个线性函数加上一定的噪声。比如说最简单的例子:有三个传感器,这三个传感器都在测量位置,这个位置在这里假设它是一个一维的信号,三个传感器都在测量位置,都带有一些噪声。这种情况下融合的规律很简单,就是求这三个测量值的平均值,也可以证明在很多意义下是最大似然,或者是最小均方误差的一个估计,这些都不是很很难。


但是问题是,如果针对这样的一个估计器,假设有一个传感器存在很大的问题,比如说有一个传感器它可能特别大或者特别小,就会把整体的估计值带偏,那么这就会产生一个非常严重的后果。


当然这个问题也可以说非常简单,因为这三个传感器都在测量同样的内容,就知道这三个传感器的测量值应该是接近的,如果其中有一个跟另外两个之间差距很大,那么我们就可以认为这个传感器是存在问题的,就可以把它剔除出去。这其实是一种叫做坏数据检测的想法,就是把跟其他数据不匹配的数据给剔除掉,这样的做法感觉上是比较简单,但是其实也不是那么简单。因为这个模型是一个非常简单的模型,就是三个传感器都在测一个同样的东西、同样的状态,因此可以说如果有一个跟其他两个差得很多,就是这个传感器有问题。但是假设我们在测不同的状态,比如说有的传感器在测这个房间的温度,有的在测走廊的温度,有的在测另一个房间的温度,那么它们之间的数据怎样叫做匹配,怎样叫做不匹配,这个问题就变得很复杂了。


再比如说,无人驾驶车的 GPS 和雷达都在测位置,但是两个位置可能是在不同时间测的,假如这个传感器告诉我现在在这里,而另外一个传感器告诉我说下一个时刻在那里,这种情况下判断这两个数据到底匹配不匹配,这个就是一个很复杂的问题。


因此,我们这个地方的想法是能否可以不用这种坏数据检测的方法,因为使用坏数据检测,首先必须要定义什么叫数据匹配。实际上,定义的一般的方法,也是先做一个状态估计,然后通过状态估计去算残差,再通过残差去确定数据是不是匹配,而我们想直接把一个好的状态估计计算出来。所以这里我们考虑这样的一个问题,z 是一个真实的传感器的估计值,我们认为这个估计值等于状态的一个线性函数加上一个噪声,可能会有一些传感器受到攻击,那么要额外在这真实的估计值上加上一个攻击项。z 里面既有噪声也有攻击,噪声一般考虑是一个比较小的数,比如像高斯可能有一个固定的方差,它不会特别大,但是噪声会影响到所有的传感器。而作为攻击来讲,我们认为攻击和噪声不一样,攻击可能是一个任意值,也就是说它可能很大也可能很小,但是这个攻击只能影响有限的传感器,比如整个系统里面有 10 个传感器,可能只有 1 个受到攻击,如果 10 个都受到攻击,当然这个系统基本上就完蛋了,所以一般只有一小部分传感器受到攻击,然后在这种情况下,我们到底应该怎么去解决这个问题。


我们提出利用凸优化的方法去求解这个问题,大概想法是:每一个传感器的测量值,当然这个测量值可能是受到攻击之后的值,假设这个系统既没有攻击也没有噪声的话,那么应该是等于。但是,因为有可能有攻击,也有可能有噪声,所以这个东西肯定是不相等的,就认为它是第个传感器的残差,肯定不是等于 0 的。那么在这种情况下,我们希望找到一个很好的 x 让残差尽可能小,就是希望去最小化这样一个残差的函数。我们在这里假设是凸的,同时它是对称的、非负的。事实上也可以证明有很多种的估计器,都可以写成这种形式,比如说刚才我们说的最小二乘估计器。


我们可以再看一些例子,比如有这样的一个问题,还是跟刚才完全一样,有三个传感器都在监测状态,然后同时有一些噪声,然后假设有一个传感器可能会受到攻击。在这种情况下,如果去优化平方的话,肯定是有问题的,因为平方得出来的是说你的状态估计应该是平均值,平均值本身是不太稳定的。但是你不去优化平方和而是优化绝对值的和,那么这样的话你的估计就会是一个中位数,中位数就是说去掉最大、去掉最小,中间的那个数,那么这样的话,应该是一个比较好的结果。


通过这个东西,我们就可以得到类似于一个安全估计的一个充分条件,就是说你需要保证两件事情,当然这个是从数学上来说比较简单的想法。就是说首先每一个人所能产生的力必须是一个有限的,这个力其实本质上来说就是斜率,就是说它的最大的斜率必须是有限的。然后,另外就是说,你任何 P 个人所产生的力一定要小于剩下的人所产生的力,因为在这里我假设有 P 个人可能是有问题的,这样的话 P 个人会有问题的话,不会把整个系统给带跑,大概是这样。当然,反过来你可以证明这两个条件也是必要的。



当然,我们后面还做了很多关于动态系统的,因为时间可能不太多,这里就不展开了。2015 年到 2018 年期间,我在新加坡,当时我们接了新加坡国防部一个关于自动驾驶的项目,他们也是比较关心自动驾驶中的安全问题,这里给大家展示的是我们在一个仿真系统上做的一些东西。


问题是这样的,现在系统里面一共是有三个用于定位的传感器:IMU、雷达、GPS。其中,这条黄色的线是 GPS 告诉我的位置,大家可以看到 GPS 逐渐偏移真实的位置,这个原因是因为我们在这个系统里面加了一个 GPS 的欺骗工具。这种工具也是比较常见,之前也有过伊朗通过 GPS 欺骗攻击,捕获了美国的一个无人机,因为那个无人机认为它已经飞到一个安全的地方,就降落了,但是其实那个地方是伊朗的占领区,然后它就被捕获了。因为 GPS 信号是一个单方向,通讯员其实是没有办法去确认 GPS 信号是不是真的,所以如果我们有一个发射器,发射一个更强的信号,把真实的 GPS 信号压过去,那么在这种情况下你得到 GPS 就是错的。


这张图是我们采用传统的信息融合方式 EKF 把 IMU、雷达、GPS 做一个融合,粉色的是我们做了一个融合的信息。这个时候,你也可以看到粉色线的已经偏出去了,最后偏的有两米左右这个距离,就大概偏出了一个车道,就因为 GPS 的信号被人劫持了。这张图是我们后面加了一些安全的设计结果,会发现当你偏得比较小的时候,你是没有办法检测出来到底是由噪声引起还是由攻击引起的。但是,如果当 GPS 偏非常大的时候,我们在这个地方就可以发现 GPS 信号是有问题的,然后我们就会把三个传感器融合变成只用雷达和 IMU 两个传感器去做融合。这样的一个效果,就等于说已经检测出来 GPS 有问题。

总结

今天讲的 Technical 的东西比较多,主要就是想跟大家聊一聊信息物理系统的安全,因为安全本身就是一个挺重要的问题。其次,从控制的角度来说,我们对这一方面的东西有一些自己的思考,可能跟传统的计算机方向相比,大家思考的方式可能也不是特别一样。但是我依然觉得,最终的一个解决方案应该是很多学科共同去协作配合,然后产生一个多层、多种角度、多种手段这样一个防御机制。


我今天主要讲的一个是入侵检测,一个是状态估计这样的两个问题。事实上这个理念单纯从控制角度来说也面临很多的挑战,现在这个领域大概也就是 10 年左右才能有一些成果,但是我觉得还是要多多学习。我希望做的一些东西,能够给真实的信息物理系统提供一些额外的安全保障。感谢大家。


作者介绍


莫一林


现任清华大学自动化系副教授。他于 2007 年在清华大学自动化系获得学士学位,2012 年于美国卡内基梅隆大学电子与计算机工程系获得博士学位。加入清华大学之前,他曾于卡内基梅隆大学,加州理工学院进行博士后研究。2015 年他加入了新加坡南洋理工大学电子与电机工程学院,任助理教授,2018 年返回清华大学自动化系任职。目前担任控制领域顶级期刊 Automatica 的 Associate Editor。他的主要研究方向包括控制系统安全与网络化控制系统,及其在智能电网、机器人与无人驾驶领域的应用。


本文转载自公众号美团技术团队(ID:meituantech)。


原文链接


清华大学莫一林:信息物理系统中的安全控制算法


2020-10-12 10:041114

评论

发布
暂无评论
发现更多内容

Android 反编译利器,jadx 的高级技巧,看完这篇彻底明白了

android 程序员 移动开发

Android Handler源码浅析,一线互联网架构师筑基必备技能之Android篇

android 程序员 移动开发

Android mvvm 之 LiveData 的原理,如何保证高可用

android 程序员 移动开发

Android 可能你想要的APK瘦身笔记(1),2021金三银四面试季

android 程序员 移动开发

Android Studio 3,2021Android面试真题精选干货整理

android 程序员 移动开发

Android WebView常见问题,androidim开发

android 程序员 移动开发

Android MVP模式深入实践探索(一),移动开发工程师简历

android 程序员 移动开发

Android Protobuf应用及原理,android输入法开发软键盘切换

android 程序员 移动开发

Android Studio自定义模板实现一键创建MVP结构,已拿到offer

android 程序员 移动开发

Android Gradle 学习笔记整理,阿里Android面试必问

android 程序员 移动开发

Android Matrix矩阵,一个Android程序员的面试心得

android 程序员 移动开发

Android P 网络请求相关总结,flutter二维码扫描插件

android 程序员 移动开发

Android 基础掌握好,面试基本不会倒!,面向Android开发者的复习指南

android 程序员 移动开发

Android WebView独立进程解决方案(1),flutter推送通知

android 程序员 移动开发

Android WebView独立进程解决方案,手撕面试官

android 程序员 移动开发

Android 可能你想要的APK瘦身笔记,android2018面试题

android 程序员 移动开发

Android 基础与底层机制面试题,万字解析

android 程序员 移动开发

Android Gradle 干货,sharedpreferences跨进程

android 程序员 移动开发

Android Manifest功能与权限描述大全,阿里大牛整理

android 程序员 移动开发

android webview与js交互(动态添加js),【好文推荐

android 程序员 移动开发

Android 关于CPU类型的so文件兼容问题(ABI),十年Android编程开发生涯

android 程序员 移动开发

Android jetpack最佳总结和实践,安卓面试题宝典app

android 程序员 移动开发

Android ViewPager2 & TabLayout,那些被大厂优化的程序员们

android 程序员 移动开发

OpenSearch 文档如何部署到 GitHub Page 中

HoneyMoose

Android 使用 Kotlin 重写 Gradle 文件,kotlin教程

android 程序员 移动开发

Android 初中级开发社招面试总结!,android自定义控件开发入门与实战

android 程序员 移动开发

Android BLE基础框架全新改版,android音视频开发面试题

android 程序员 移动开发

Android Gradle 常用配置,androidsdk环境配置

android 程序员 移动开发

Android NDK 开发之 CMake 必知必会,程序员必须要了解的知识点

android 程序员 移动开发

OpenSearch 文档中文本地化

HoneyMoose

Android JPEG 压缩那些事,深入解析Android-AutoLayout

android 程序员 移动开发

清华大学莫一林:信息物理系统中的安全控制算法_安全_莫一林_InfoQ精选文章