[转载] Android A/B System OTA分析(一)概览

原创

Android A/B System OTA分析(一)概览

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/guyongqiangx/article/details/71334889

Android从7.0开始引入新的OTA升级方式,A/B System Updates,这里将其叫做A/B系统。

版权声明:
本文为guyongqiangx原创,欢迎转载,请注明出处:
Android A/B System OTA分析(一)概览: http://blog.csdn.net/guyongqiangx/article/details/71334889

A/B系统涉及的内容较多,分多篇对A/B系统的各个方面进行分析。本文为第一篇,概览。

1. A/B系统的特点

顾名思义,A/B系统就是设备上有AB两套可以工作的系统(用户数据只有一份,为两套系统共用),简单来讲,可以理解为一套系统分区,另外一套为备份分区。其系统版本可能一样;也可能不一样,其中一个是新版本,另外一个旧版本,通过升级,将旧版本也更新为新版本。当然,设备出厂时这两套系统肯定是一样的。

之所以叫套,而不是个,是因为Android系统不是由一个分区组成,其系统包括boot分区的kernel和ramdisk,systemvendor分区的应用程序和库文件,以及userdata分区的数据

A/B系统实现了无缝升级(seamless updates),有以下特点:

  • 出厂时设备上有两套可以正常工作的系统,升级时确保设备上始终有一个可以工作的系统,减少设备变砖的可能性,方便维修和售后。
  • OTA升级在Android系统的后台进行,所以更新过程中,用户可以正常使用设备,数据更新完成后,仅需要用户重启一次设备进入新系统
  • 如果OTA升级失败,设备可以回退到升级前的旧系统,并且可以尝试再次更新升级。

Android 7.0上传统OTA方式和新的A/B系统方式都存在,只是编译时只能选择其中的一种OTA方式。由于A/B系统在分区上与传统OTA的分区设计不一样,二者无法兼容,所以7.0以前的系统无法通过OTA方式升级为A/B系统。

啰嗦一下7.0以前传统的OTA方式:

设备上有一个Android主系统和一个Recovery系统,Android主系统运行时检测是否需要升级,如果需要升级,则将升级的数据包下载并存放到cache分区,重启系统后进入Recovery系统,并用cache分区下载好的数据更新Android主系统,更新完成后重新启动进入Android主系统。如果更新失败,设备重启后就不能正常使用了,唯一的办法就是重新升级,直到成功为止。

A/B系统主要由运行在Android后台的update_engine和两套分区‘slot A’‘slot B’组成。Android系统从其中一套分区启动,在后台运行update_engine监测升级信息并下载升级数据,然后将数据更新到另外一套分区,写入数据完成后从更新的分区启动。

与传统OTA方式相比,A/B系统的变化主要有:

  1. 系统的分区设置
    • 传统方式只有一套分区
    • A/B系统有两套分区,称为slot Aslot B
  2. 跟bootloader沟通的方式
    • 传统方式bootloader通过读取misc分区信息来决定是进入Android主系统还是Recovery系统
    • A/B系统的bootloader通过特定的分区信息来决定从slot A还是slot B启动
  3. 系统的编译过程
    • 传统方式在编译时会生成boot.imgrecovery.img分别用于Android主系统和Recovery系统的ramdisk
    • A/B系统只有boot.img,而不再生成单独的recovery.img
  4. OTA更新包的生成方式
    • A/B系统生成OTA包的工具和命令跟传统方式一样,但是生成内容的格式不一样了

由于内容较多,分多篇文章来详细分析整个A/B系统。

本文主要从分区和总体操作流程上来描述A/B系统,也可以参考Android官方对A/B系统的说明:"A/B System Updates"

2. A/B系统的分区

2.1 传统OTA的分区

传统OTA方式下的分区主要包括:

  • bootloader

    存放用于引导linux的bootloader

  • boot

    存放Android主系统的linux kernel文件和用于挂载system和其他分区的ramdisk

  • system

    Android主系统分区,包括Android的系统应用程序和库文件

  • vendor

    Android主系统分区,主要是包含开发厂商定制的一些应用和库文件,很多时候开发厂商也直接将这个分区的内容直接放入system分区

  • userdata

    用户数据分区,存放用户数据,包括用户安装的应用程序和使用时生成的数据

  • cache

    临时存放数据的分区,通常用于存放OTA的升级包

  • recovery

    存放Recovery系统的linux kernel文件和ramdisk

  • misc

    存放Android主系统和Recovery系统跟bootloader通信的数据

2.2 A/B系统的分区

  • bootloader

    存放用于引导linux的bootloader

  • boot_aboot_b

    分别用于存放两套系统各自的linux kernel文件和用于挂载system和其他分区的ramdisk

  • system_asystem_b

    Android主系统分区,分别用于存放两套系统各自的系统应用程序和库文件

  • vendor_avendor_b

    Android主系统分区, 分别用于存放两套系统各自的开发厂商定制的一些应用和库文件,很多时候开发厂商也直接将这个分区的内容直接放入system分区

  • userdata

    用户数据分区,存放用户数据,包括用户安装的应用程序和使用时生成的数据

  • misc或其他名字分区

    存放Android主系统和Recovery系统跟bootloader通信的数据,由于存放方式和分区名字没有强制要求,所以部分实现上保留了misc分区(代码中可见BrilloIntel的平台),另外部分实现采用其他分区存放数据(Broadcom机顶盒平台采用名为eio的分区)。

2.3 一张图比较传统分区和A/B系统分区

关于分区的区别,文字描述不够直观,采用图片清楚多了。

Legacy Partitions VS. A/B System Partitions

主要区别在于A/B系统:

  1. bootsystemvendor系统分区从传统的一套变为两套,叫做slot Aslot B
  2. 不再需要cacherecovery分区
  3. misc分区不是必须

关于cachemisc分区:

  • 仍然有部分厂家保留cache分区,用于一些其他的用途,相当于temp文件夹,但不是用于存放下载的OTA数据。
  • 部分厂家使用misc分区存放Android系统同bootloader通信数据,另有部分厂家使用其它名字的分区存储这类数据。

3. A/B系统的状态

3.1 系统分区属性

对于A/B系统的slot Aslot B分区,其都存在以下三个属性:

  • active

    系统的活动分区标识,这是一个排他属性,系统只能有一个分区设置为active属性,启动时bootloader选取设置为active的分区进行启动。

  • bootable

    分区可启动标识,设置为bootable的分区表明该分区包含了一个完整的可以启动的系统。

  • successful

    分区成功运行标识,设置为successful的分区表明该分区在上一次启动或当前启动中可以正确运行。

3.2 系统的典型场景

典型的应用场景有以下4个(假定当前从B分区启动):

A/B System Example Scenarios

图中:

  • 当前运行的系统(current)用绿色方框表示,当前没有用的系统(unused)用灰色方框表示。
  • 属性标识为红色,表示该状态下相应属性被设置,标识为灰色标识该状态下属性没有设置或设置为相反属性,如:
    • active” 表示已经设置active属性,当前为活动分区;”active” 表示没有设置active属性
    • bootable” 表示已经设置bootable属性;”bootable” 表示设置为unbootable或没有设置bootable属性
    • successful” 表示已经设置successful属性,”successful” 表示没有设置successful属性

每个场景详细说明如下:

  1. 普通场景(Normal cases

    最常见的情形,例如设备出厂时,A分区和B分区都可以成功启动并正确运行,所以两个分区都设置为bootablesuccessful,但由于是从B分区启动,所以只有B分区设置为active

  2. 升级中(Update in progress

    B分区检测到升级数据,在A分区进行升级,此时将A分区标识为unbootable,另外清除successful标识;B分区仍然为activebootablesuccessful

  3. 更新完成,等待重启(Update applied, reboot pending

    B分区将A分区成功更新后,将A分区标识为bootable。另外,由于重启后需要从A分区启动,所以也需要将A分区设置为active,但是由于还没有验证过A分区是否能成功运行,所以不设置successful;B分区的状态变为bootablesuccessful,但没有active

  4. 从新系统成功启动(System rebooted into new update

    设备重启后,bootloader检测到A分区为active,所以加载A分区系统。进入A系统后如果能正确运行,需要将A分区标识为successful。对比第1个普通场景,A和B系统都设置为bootablesuccessful,但active从B分区切换到A分区。至此,B分区成功更新并切换到A分区,设备重新进入普通场景。

4. A/B系统的更新流程

整个A/B系统的升级更新在后台完成,升级中任何时间点都是可中断和可恢复的,相当于下载中的断点续传,更新操作对用户是透明的,在不影响用户操作的情况下完成升级。

设备可以设置数据下载、更新升级的场景和策略,例如:

  • 只有在WiFi连接时才下载数据
  • 电量较少时不下载数据、不进行更新
  • 用户没有活动时才进行数据下载和更新等

具体有哪些策略依赖于开发者和用户的设置。

<<未完,待续>>

联系和福利

  • 关注微信公众号“洛奇看世界”

    • 回复关键词“Android电子书”,获取超过150本Android相关的电子书和文档。电子书包含了Android开发相关的方方面面,从此你再也不需要到处找Android开发的电子书了。

    image


  • 个人微信号,添加请备注“微信公众号”。

    image

文章最后发布于: 2017-05-07 16:31:57
        <!--打赏开始-->
                <div class="reward-user-box" style="margin-top: -12px;">
            <span class="reward-word" style="color:#B4B4B4 !important">有 <span class="num">0</span> 个人打赏</span>
                        </div>
            <!--打赏结束-->
    <div class="recommend-box"><div class="recommend-item-box type_blog clearfix" data-report-click="{&quot;mod&quot;:&quot;popu_614&quot;,&quot;dest&quot;:&quot;https://blog.csdn.net/liyuchong2537631/article/details/97516299&quot;,&quot;strategy&quot;:&quot;BlogCommendFromBaidu&quot;,&quot;index&quot;:&quot;0&quot;}">
<div class="content" style="width: 852px;">
	<a href="https://blog.csdn.net/liyuchong2537631/article/details/97516299" target="_blank" rel="noopener" title="android P  OTA 初探 —— 1、OTA简单介绍">
	<h4 class="text-truncate oneline" style="width: 692px;">
			<em>android</em> P  <em>OTA</em> 初探 —— 1、<em>OTA</em>简单介绍		</h4>
	<div class="info-box d-flex align-content-center">
		<p class="date-and-readNum oneline">
			<span class="date hover-show">07-27</span>
			<span class="read-num hover-hide">
				阅读数 
				159</span>
			</p>
		</div>
	</a>
	<p class="content" style="width: 852px;">
		<a href="https://blog.csdn.net/liyuchong2537631/article/details/97516299" target="_blank" rel="noopener" title="android P  OTA 初探 —— 1、OTA简单介绍">
			<span class="desc oneline">本系列介绍自己理解的基于androidP的OTA系统。由于工作需要开始研究,实践经验匮乏,难免有理解不够或者错误之处。还请多多指正,不吝赐教!1、本文提及的OTA指的是android手机的基础操作系统...</span>
		</a>
		<span class="blog_title_box oneline ">
								<span class="type-show type-show-blog type-show-after">博文</span>
										<a target="_blank" rel="noopener" href="https://blog.csdn.net/liyuchong2537631">来自:	<span class="blog_title"> 思念叨火车的专栏</span></a>
											</span>
	</p>
</div>
</div>
<div class="comment-list-container">
	<a id="comments"></a>
	<div class="comment-list-box" style="max-height: 275px;"><ul class="comment-list"><li class="comment-line-box d-flex" data-commentid="10266609" data-replyname="weixin_41445310">      <a target="_blank" href="https://me.csdn.net/weixin_41445310"><img src="https://avatar.csdn.net/2/7/8/3_weixin_41445310.jpg" username="weixin_41445310" alt="weixin_41445310" class="avatar"></a>        <div class="right-box ">          <div class="new-info-box clearfix">            <a target="_blank" href="https://me.csdn.net/weixin_41445310"><span class="name ">weixin_41445310</span></a><span class="date" title="2019-07-28 16:20:41">2个月前</span><span class="floor-num">#9楼</span><span class="new-comment">比如我现在可以查到自己在slota下运行,是否可以将slotb的系统分区删除,来节约空间?</span><span class="new-opt-box"><a class="btn btn-link-blue btn-report" data-type="report">举报</a><a class="btn btn-link-blue btn-reply" data-type="reply">回复</a><a class="btn btn-link-blue btn-read-reply" data-type="readreply">查看回复(2)</a></span></div><div class="comment-like " data-commentid="10266609"><svg t="1569296798904" class="icon " viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="5522" width="200" height="200"><path d="M726.016 906.666667h-348.586667a118.016 118.016 0 0 1-116.992-107.904l-29.013333-362.666667A117.589333 117.589333 0 0 1 348.458667 309.333333H384c126.549333 0 160-104.661333 160-160 0-51.413333 39.296-88.704 93.397333-88.704 36.906667 0 71.68 18.389333 92.928 49.194667 26.88 39.04 43.178667 111.658667 12.714667 199.509333h95.530667a117.418667 117.418667 0 0 1 115.797333 136.106667l-49.28 308.522667a180.608 180.608 0 0 1-179.072 152.704zM348.458667 373.333333l-4.48 0.170667a53.461333 53.461333 0 0 0-48.768 57.472l29.013333 362.666667c2.218667 27.52 25.6 49.024 53.205333 49.024h348.544a116.949333 116.949333 0 0 0 115.925334-98.816l49.322666-308.736a53.418667 53.418667 0 0 0-52.650666-61.781334h-144.085334a32 32 0 0 1-28.458666-46.634666c45.909333-89.130667 28.885333-155.434667 11.562666-180.522667a48.981333 48.981333 0 0 0-40.192-21.504c-6.912 0-29.397333 1.792-29.397333 24.704 0 111.317333-76.928 224-224 224h-35.541333zM170.624 906.666667a32.042667 32.042667 0 0 1-31.872-29.44l-42.666667-533.333334a32.042667 32.042667 0 0 1 29.354667-34.474666c17.066667-1.408 33.024 11.733333 34.432 29.354666l42.666667 533.333334a32.042667 32.042667 0 0 1-31.914667 34.56z" p-id="5523"></path></svg><span></span></div></div></li><li class="replay-box"><ul class="comment-list"><li class="comment-line-box d-flex" data-commentid="10608757" data-replyname="weixin_41445310">      <a target="_blank" href="https://me.csdn.net/weixin_41445310"><img src="https://avatar.csdn.net/2/7/8/3_weixin_41445310.jpg" username="weixin_41445310" alt="weixin_41445310" class="avatar"></a>        <div class="right-box reply-box">          <div class="new-info-box clearfix">            <a target="_blank" href="https://me.csdn.net/weixin_41445310"><span class="name mr-8">weixin_41445310</span></a><span class="text">回复</span>  <span class="nick-name">书剑飘零-Heize</span><span class="date" title="2019-09-23 13:35:06">3周前</span><span class="text"></span><span class="new-comment">

我尝试在twrp下删除过OTA分区,结果通过刷底包中的partition gpt、bootloader bootloader、fsg fsg才恢复过来,不然就开机进不了系统举报回复

  • hhp5127447
    书剑飘零-Heize回复 weixin_414453102个月前
    分区不是你想删就可以删的哇。这里涉及很多东西。分区表,启动项等。都是关键的东西。别乱来。除非你系统一开始就是单分区的。
    举报回复
    • hhp5127447
      书剑飘零-Heize1年前#8楼想问下,整个升级结束之后,系统是启动哪个system分区?
      比如:
      升级前:system_a(正在运行分区),system_b(备份分区)
      整个升级流程结束之后启动的分区?是system_a?还是system_b?
      举报回复查看回复(8)
      • u010041075
        Zz_patrick回复 guyongqiangx2个月前
        这个问题其实官方有解释的, 的确如你所说有一个同步过程. 这个同步过程是在你去服务器取升级包之前.
        举报回复
      • guyongqiangx
        guyongqiangx回复 书剑飘零-Heize1年前我的理解是短时间版本不一致并不会有什么影响。例如,将B分区升级到新版本,此时A分区还是旧版本,如果新升级的B分区有问题,此时可以很容易通过将active设置为A进行回退。从长时间来说,B分区升级后,A分区也是要升级的。我个人的理解是,此时A分区可以同步B分区的内容,也可以直接进行OTA下载。我只读过部分代码,所以无法详细描述细节。举报回复
      • hhp5127447
        书剑飘零-Heize回复 guyongqiangx1年前我也看了官方说明,确实你的跟官方的是一样的,这可能需要再研究下具体代码才能清楚如何同步了。举报回复
      • guyongqiangx
        guyongqiangx回复 书剑飘零-Heize1年前这部分升级逻辑跟update_engine相关,我并没有读完update_engine全部代码,所以不知道每一个细节,因此我这里说的并不都是对的。目前我看过的update_engine_client代码只负责让某个分区进行升级,也没有同步的问题。至于如何同步,可能需要你去看下代码。
        前面也提到了升级的场景,这个升级场景来自google的官方描述,见本文第二个图。我不清楚“谷歌原生里,A与B在每一次的升级最后,都会是一样的,不可能存在不一样的情况。如果存在不一样的版本,那么下次升级的时候必定是混乱的”你的这个结论是如何来的哈,为什么不能存在版本不一致的情况,不一致的时候再升级就好了,因为升级完B分区后,会设置B分区为active,以后启动一直都会使用B分区,除非此时升级A分区,并将A分区设置为active分区,否则,不会从A分区启动的。
        举报回复
      • hhp5127447
        书剑飘零-Heize回复 guyongqiangx1年前这个回答有点不合逻辑了。
        首先,如果A运行升级B,而不在这次升级中同步A的话,那么A与B就是版本不一样了。并且,谷歌原生里,A与B在每一次的升级最后,都会是一样的,不可能存在不一样的情况。如果存在不一样的版本,那么下次升级的时候必定是混乱的!
        再者,上层应用并不会同一个版本触发两次升级,因为上层应用能够读取到的是运行中的分区的版本号,没有权限去读取备份分区的版本号。
        最后,我觉得你这个AB分区运行的切换逻辑分析得有点问题,A升级B,启动后运行B,如果不做同步,A就会维持原版本。那么,上层应用下次升级读取到的版本号是B的版本号!试问,如果是个差分包,A分区如何成功升级?这里就存在很大的问题。用B的版本号获取的差分包必定是以B分区版本作为原始版本的差分包,而A分区则是更原始的版本。
        举报回复
      • guyongqiangx
        guyongqiangx回复 书剑飘零-Heize1年前这个应该由应用去检测什么时候需要升级,从而设置升级标识。我看的这个是原生的Android,也还没有深入去分析update_engine部分代码。举报回复
      • hhp5127447
        书剑飘零-Heize回复 guyongqiangx1年前按照你的说法,A分区运行时升级B分区,重启启动B分区。那么,什么时候将A分区同步?有没有触发接口或者标志?举报回复
      • guyongqiangx
        guyongqiangx回复 书剑飘零-Heize1年前根据升级场景,A分区运行升级B分区,更新后会将B分区设置为Active,因此启动后会进入B分区才算完成整个升级。举报回复
    • xhg9638197
      seclen3个月前#7楼感谢博主,有个问题想请教下,android的分区这是由各设备厂商自己定义的吧,boot也是由设备厂商定义的吧,设备厂商可以使用传统的分区也可以使用A/B分区,跟android版本有什么关系吗,举报回复查看回复(1)
      • u010041075
        Zz_patrick回复 seclen2个月前
        设备厂商可以自己定义, 在后面的安卓版本中不遵循A/B分区的升级方式. 只是在android 8.x后面的版本,Ggoole对A/B OTA升级的方式有完整的支持,并建议设备厂商使用该种方式.
        举报回复
    • s418358827
      s4183588279个月前#5楼感谢博主分享,请教一个问题。
      升级,更新,标记分区为bootable、successful都是update_engine做的吗?
      举报回复
    • yyytso
      yyytso1年前#4楼博主,有两个问题请教一下:1. 添加所需的配置,编译生成只有一个systemimg和bootimg这是正确的吗,2. 如何判断已经是开启AB了举报回复
    • siyolatte
      siyolatte1年前#2楼两个问题想请教博主:
      1,你在系统的典型场景介绍了正常更新流程,如果新系统启动失败,A系统起不来,其处理流程是什么样的?我理解A起不来应该把active设置到B系统,这个设置过程是在系统哪个阶段做的?
      2,AB分区只是在system,vendor,boot有两套,如果更新这三个之外的分区呢?后台更新不重启的话系统可能会crash吧?这种情况该怎么办
      举报回复查看回复(2)
      • siyolatte
        siyolatte回复 guyongqiangx1年前非常感谢。然后你的意思是对于自定义的分区也可以自己实现AB两套,不限于system,vendor,boot这三个是吗举报回复
      • guyongqiangx
        guyongqiangx回复 siyolatte1年前抱歉,有段时间了,我已经不太记得技术的细节了。关于问题1,可以考虑在bootloader里面处理,例如在启动信息里面存放一个计数器,初始值为3,每次启动的时候bootloader可以将其递减1,在启动成功进入应用后将其复位为3。所有如果不能启动,那这个技术值就会逐渐变为3,2,1,0,当bootloader发现这个值为0时,就切换到另外一个分区启动。这只是一种思路,官方并没有对这个实现做强制要求;问题2. 不清楚你有什么东西需要放在一个单独的分区里面,我感觉system, vendor和boot分区已经可以满足要求了,对于data分区的用户数据是不需要升级的。当然,你也可以参照这个对需要的分区也实行A/B备份,如果都有A/B分区的话,启动后是不应该有crash的。举报回复

    • 上一页
    • 1
    • 下一页




    <div class="recommend-item-box recommend-recommend-box"><div id="kp_box_60" data-pid="60"><iframe src="https://adaccount.csdn.net/#/preview/645?m=cQbEinJbtiQHnbLcpDEAiStpJAyStSnLbHtcDmbbbQpbLHXQiJHtbSXintfbvHJnbJnbpLSQEtWcbHnLJpJcAAJiSpEpEbQAbEJQ&amp;k=" frameborder="0" width="100%" height="75px" scrolling="no"></iframe><img class="pre-img-lasy" data-src="https://kunyu.csdn.net/1.png?d=2&amp;k=&amp;m=cQbEinJbtiQHnbLcpDEAiStpJAyStSnLbHtcDmbbbQpbLHXQiJHtbSXintfbvHJnbJnbpLSQEtWcbHnLJpJcAAJiSpEpEbQAbEJQ"></div></div>
    
    		<div class="recommend-item-box blog-expert-recommend-box" style="display: block;">
    		<div class="d-flex">
    			<div class="blog-expert-recommend">
    				<div class="blog-expert">
    					<div class="blog-expert-flexbox" data-report-view="{&quot;mod&quot;:&quot;popu_709&quot;,&quot;dest&quot;:&quot;https://blog.csdn.net/guyongqiangx/article/details/71334889&quot;}"><div class="blog-expert-item"><div class="blog-expert-info-box"><div class="blog-expert-img-box" data-report-click="{&quot;mod&quot;:&quot;popu_709&quot;,&quot;dest&quot;:&quot;https://blog.csdn.net/guyongqiangx/article/details/71334889&quot;}"><a href="https://blog.csdn.net/liyuchong2537631" target="_blank"><img src="https://avatar.csdn.net/7/0/C/3_liyuchong2537631.jpg" username="liyuchong2537631" alt="思念叨火车" title="思念叨火车"></a><span data-report-click="{&quot;mod&quot;:&quot;popu_710&quot;,&quot;dest&quot;:&quot;https://blog.csdn.net/guyongqiangx/article/details/71334889&quot;}"><span class="blog-expert-button-follow btn-red-follow" data-name="liyuchong2537631" data-nick="思念叨火车">关注</span></span></div><div class="info"><span data-report-click="{&quot;mod&quot;:&quot;popu_709&quot;,&quot;dest&quot;:&quot;https://blog.csdn.net/guyongqiangx/article/details/71334889&quot;}"><a href="https://blog.csdn.net/liyuchong2537631" target="_blank"><h5 class="oneline" title="思念叨火车">思念叨火车</h5></a></span>  <p></p><p class="article-num" title="91篇文章"> 91篇文章</p><p class="article-num" title="排名:千里之外"> 排名:千里之外</p><p></p></div></div></div><div class="blog-expert-item"><div class="blog-expert-info-box"><div class="blog-expert-img-box" data-report-click="{&quot;mod&quot;:&quot;popu_709&quot;,&quot;dest&quot;:&quot;https://blog.csdn.net/guyongqiangx/article/details/71334889&quot;}"><a href="https://blog.csdn.net/ch853199769" target="_blank"><img src="https://avatar.csdn.net/A/6/D/3_ch853199769.jpg" username="ch853199769" alt="安德路" title="安德路"></a><span data-report-click="{&quot;mod&quot;:&quot;popu_710&quot;,&quot;dest&quot;:&quot;https://blog.csdn.net/guyongqiangx/article/details/71334889&quot;}"><span class="blog-expert-button-follow btn-red-follow" data-name="ch853199769" data-nick="安德路">关注</span></span></div><div class="info"><span data-report-click="{&quot;mod&quot;:&quot;popu_709&quot;,&quot;dest&quot;:&quot;https://blog.csdn.net/guyongqiangx/article/details/71334889&quot;}"><a href="https://blog.csdn.net/ch853199769" target="_blank"><h5 class="oneline" title="安德路">安德路</h5></a></span>  <p></p><p class="article-num" title="105篇文章"> 105篇文章</p><p class="article-num" title="排名:千里之外"> 排名:千里之外</p><p></p></div></div></div><div class="blog-expert-item"><div class="blog-expert-info-box"><div class="blog-expert-img-box" data-report-click="{&quot;mod&quot;:&quot;popu_709&quot;,&quot;dest&quot;:&quot;https://blog.csdn.net/guyongqiangx/article/details/71334889&quot;}"><a href="https://blog.csdn.net/u014248312" target="_blank"><img src="https://avatar.csdn.net/A/9/4/3_u014248312.jpg" username="u014248312" alt="深海Enoch" title="深海Enoch"></a><span data-report-click="{&quot;mod&quot;:&quot;popu_710&quot;,&quot;dest&quot;:&quot;https://blog.csdn.net/guyongqiangx/article/details/71334889&quot;}"><span class="blog-expert-button-follow btn-red-follow" data-name="u014248312" data-nick="深海Enoch">关注</span></span></div><div class="info"><span data-report-click="{&quot;mod&quot;:&quot;popu_709&quot;,&quot;dest&quot;:&quot;https://blog.csdn.net/guyongqiangx/article/details/71334889&quot;}"><a href="https://blog.csdn.net/u014248312" target="_blank"><h5 class="oneline" title="深海Enoch">深海Enoch</h5></a></span>  <p></p><p class="article-num" title="59篇文章"> 59篇文章</p><p class="article-num" title="排名:千里之外"> 排名:千里之外</p><p></p></div></div></div><div class="blog-expert-item"><div class="blog-expert-info-box"><div class="blog-expert-img-box" data-report-click="{&quot;mod&quot;:&quot;popu_709&quot;,&quot;dest&quot;:&quot;https://blog.csdn.net/guyongqiangx/article/details/71334889&quot;}"><a href="https://blog.csdn.net/2066" target="_blank"><img src="https://avatar.csdn.net/6/F/4/3_2066.jpg" username="2066" alt="2066" title="2066"></a><span data-report-click="{&quot;mod&quot;:&quot;popu_710&quot;,&quot;dest&quot;:&quot;https://blog.csdn.net/guyongqiangx/article/details/71334889&quot;}"><span class="blog-expert-button-follow btn-red-follow" data-name="2066" data-nick="2066">关注</span></span></div><div class="info"><span data-report-click="{&quot;mod&quot;:&quot;popu_709&quot;,&quot;dest&quot;:&quot;https://blog.csdn.net/guyongqiangx/article/details/71334889&quot;}"><a href="https://blog.csdn.net/2066" target="_blank"><h5 class="oneline" title="2066">2066</h5></a></span>  <p></p><p class="article-num" title="78篇文章"> 78篇文章</p><p class="article-num" title="排名:千里之外"> 排名:千里之外</p><p></p></div></div></div></div>
    				</div>
    			</div>
    		</div>
    	</div><div class="recommend-item-box baiduSearch recommend-box-ident" data-report-view="{&quot;mod&quot;:&quot;popu_614&quot;,&quot;dest&quot;:&quot;https://blog.csdn.net/weixin_33912453/article/details/87374554&quot;,&quot;strategy&quot;:&quot;searchFromBaidu1&quot;,&quot;index&quot;:&quot;6&quot;}" data-report-click="{&quot;mod&quot;:&quot;popu_614&quot;,&quot;dest&quot;:&quot;https://blog.csdn.net/weixin_33912453/article/details/87374554&quot;,&quot;strategy&quot;:&quot;searchFromBaidu1&quot;,&quot;index&quot;:&quot;6&quot;}" data-track-view="{&quot;mod&quot;:&quot;popu_614&quot;,&quot;dest&quot;:&quot;https://blog.csdn.net/weixin_33912453/article/details/87374554&quot;,&quot;strategy&quot;:&quot;searchFromBaidu1&quot;,&quot;index&quot;:4,&quot;extend1&quot;:&quot;_&quot;}" data-track-click="{&quot;mod&quot;:&quot;popu_614&quot;,&quot;dest&quot;:&quot;https://blog.csdn.net/weixin_33912453/article/details/87374554&quot;,&quot;strategy&quot;:&quot;searchFromBaidu1&quot;,&quot;index&quot;:4,&quot;extend1&quot;:&quot;_&quot;}" data-flg="true">                <a href="https://blog.csdn.net/weixin_33912453/article/details/87374554" target="_blank">              		<h4 class="text-truncate oneline" style="width: 772px;"><em>Android</em> <em>A</em>/<em>B</em> <em>System</em> <em>OTA</em> 本地测试方法 - weixin_339124..._CSDN博客</h4>                  <div class="info-box d-flex align-content-center">                    <p>                      <span class="date">2-17</span>                    </p>                  </div>                </a>            	</div><div class="recommend-item-box baiduSearch recommend-box-ident" data-report-view="{&quot;mod&quot;:&quot;popu_614&quot;,&quot;dest&quot;:&quot;https://blog.csdn.net/sir_zeng/article/details/79044121&quot;,&quot;strategy&quot;:&quot;searchFromBaidu1&quot;,&quot;index&quot;:&quot;8&quot;}" data-report-click="{&quot;mod&quot;:&quot;popu_614&quot;,&quot;dest&quot;:&quot;https://blog.csdn.net/sir_zeng/article/details/79044121&quot;,&quot;strategy&quot;:&quot;searchFromBaidu1&quot;,&quot;index&quot;:&quot;8&quot;}" data-track-view="{&quot;mod&quot;:&quot;popu_614&quot;,&quot;dest&quot;:&quot;https://blog.csdn.net/sir_zeng/article/details/79044121&quot;,&quot;strategy&quot;:&quot;searchFromBaidu1&quot;,&quot;index&quot;:5,&quot;extend1&quot;:&quot;_&quot;}" data-track-click="{&quot;mod&quot;:&quot;popu_614&quot;,&quot;dest&quot;:&quot;https://blog.csdn.net/sir_zeng/article/details/79044121&quot;,&quot;strategy&quot;:&quot;searchFromBaidu1&quot;,&quot;index&quot;:5,&quot;extend1&quot;:&quot;_&quot;}" data-flg="true">                <a href="https://blog.csdn.net/sir_zeng/article/details/79044121" target="_blank">              		<h4 class="text-truncate oneline" style="width: 772px;"><em>Android</em> <em>A</em>/<em>B</em> <em>System</em> 浅析 - sir_zeng的专栏 - CSDN博客</h4>                  <div class="info-box d-flex align-content-center">                    <p>                      <span class="date">4-14</span>                    </p>                  </div>                </a>            	</div>
    
    <div class="recommend-item-box recommend-box-ident recommend-download-box clearfix" data-report-view="{&quot;mod&quot;:&quot;popu_614&quot;,&quot;dest&quot;:&quot;https://download.csdn.net/download/linghuncangsang/6664547&quot;,&quot;strategy&quot;:&quot;BlogCommendFromBaidu&quot;,&quot;index&quot;:&quot;13&quot;}" data-report-click="{&quot;mod&quot;:&quot;popu_614&quot;,&quot;dest&quot;:&quot;https://download.csdn.net/download/linghuncangsang/6664547&quot;,&quot;strategy&quot;:&quot;BlogCommendFromBaidu&quot;,&quot;index&quot;:&quot;13&quot;}">
    	<a href="https://download.csdn.net/download/linghuncangsang/6664547" rel="noopener" target="_blank">
    		<div class="content clearfix">
    			<div class="">
    				<h4 class="text-truncate oneline clearfix">
    					linux 发包					</h4>
    				<span class="data float-right">12-05</span>
    			</div>
    			<div class="desc oneline">
    					# ./DoSend -h Usage: ./DoSend # ./DoSend -v ./DoSend ver 1.10 # TCP测试 &lt;attackmode&gt; 0 尽最大可能持续发送TCP包,这				</div>
    			<span class="type-show type-show-download">下载</span>
    		</div>
    	</a>
    </div>
    
    <div class="recommend-item-box recommend-recommend-box"><div id="kp_box_61" data-pid="61"><div style=""><iframe width="852" frameborder="0" height="66" scrolling="no" src="https://pos.baidu.com/s?hei=66&amp;wid=852&amp;di=u3600846&amp;ltu=https%3A%2F%2Fblog.csdn.net%2Fguyongqiangx%2Farticle%2Fdetails%2F71334889&amp;psi=bb3c0f51e5fca292318a56f3a60b26d7&amp;dis=0&amp;dai=3&amp;pcs=1345x587&amp;par=1366x720&amp;dtm=HTML_POST&amp;cfv=0&amp;cpl=21&amp;dri=0&amp;cec=UTF-8&amp;pis=-1x-1&amp;chi=50&amp;dc=3&amp;drs=1&amp;ari=2&amp;pss=1345x8306&amp;ti=Android%20A%2FB%20System%20OTA%E5%88%86%E6%9E%90%EF%BC%88%E4%B8%80%EF%BC%89%E6%A6%82%E8%A7%88&amp;cce=true&amp;prot=2&amp;cmi=39&amp;cdo=-1&amp;tcn=1571407096&amp;tpr=1571407096295&amp;ant=0&amp;tlm=1571407096&amp;psr=1366x768&amp;exps=111000,110011&amp;cja=false&amp;col=zh-CN&amp;ccd=24&amp;ps=7357x378"></iframe></div><script type="text/javascript" src="//rabc1.iteye.com/common/web/production/79m9.js?f=aszggcwz"></script><img class="pre-img-lasy" data-src="https://kunyu.csdn.net/1.png?p=61&amp;a=622&amp;c=0&amp;k=&amp;d=1&amp;t=3&amp;u=297c1e7260ea4d1399225c012fc66f94"></div></div>
    
    <div class="recommend-item-box recommend-recommend-box"><div id="kp_box_62" data-pid="62"><script type="text/javascript">
    (function() {
        var s = "_" + Math.random().toString(36).slice(2);
        document.write('<div style="" id="' + s + '"></div>');
        (window.slotbydup = window.slotbydup || []).push({
            id: "u3600849",
            container:  s
        });
    })();
    

    <div class="recommend-item-box recommend-recommend-box"><div id="kp_box_63" data-pid="63"><script type="text/javascript">
        (function() {
            var s = "_" + Math.random().toString(36).slice(2);
            document.write('<div style="" id="' + s + '"></div>');
            (window.slotbydup = window.slotbydup || []).push({
                id: "u4221910",
                container: s
            });
        })();
    

    <div class="recommend-item-box recommend-recommend-box"><div id="kp_box_64" data-pid="64"><script type="text/javascript">
    (function() {
        var s = "_" + Math.random().toString(36).slice(2);
        document.write('<div style="" id="' + s + '"></div>');
        (window.slotbydup = window.slotbydup || []).push({
            id: "u3600856",
            container:  s
        });
    })();
    

    <div class="recommend-item-box recommend-recommend-box"><div id="kp_box_65" data-pid="65"><script type="text/javascript">
        (function() {
            var s = "_" + Math.random().toString(36).slice(2);
            document.write('<div style="" id="' + s + '"></div>');
            (window.slotbydup = window.slotbydup || []).push({
                id: "u4221803",
                container: s
            });
        })();
    

    <div class="recommend-item-box recommend-recommend-box"><div id="kp_box_66" data-pid="66"><div id="three_ad38" class="mediav_ad"></div>
    

    <div class="recommend-item-box recommend-recommend-box"><div style=""><div style="margin-left:0px;"><iframe width="852" frameborder="0" height="60" scrolling="no" src="https://pos.baidu.com/s?hei=60&amp;wid=852&amp;di=u3491668&amp;ltu=https%3A%2F%2Fblog.csdn.net%2Fguyongqiangx%2Farticle%2Fdetails%2F71334889&amp;psi=bb3c0f51e5fca292318a56f3a60b26d7&amp;pis=-1x-1&amp;dtm=HTML_POST&amp;chi=50&amp;cmi=39&amp;pcs=1345x587&amp;ps=10256x378&amp;dai=7&amp;exps=111000,110011&amp;cpl=21&amp;pss=1345x10309&amp;ant=0&amp;tpr=1571407096295&amp;ti=Android%20A%2FB%20System%20OTA%E5%88%86%E6%9E%90%EF%BC%88%E4%B8%80%EF%BC%89%E6%A6%82%E8%A7%88&amp;dis=0&amp;psr=1366x768&amp;drs=1&amp;tcn=1571407096&amp;dri=1&amp;cfv=0&amp;ari=2&amp;tlm=1571407096&amp;ccd=24&amp;prot=2&amp;par=1366x720&amp;dc=3&amp;col=zh-CN&amp;cce=true&amp;cec=UTF-8&amp;cja=false&amp;cdo=-1"></iframe><em id="wudcnjqj" style="display:none;text-align:left;"></em></div></div><script type="text/javascript" src="//rabc1.iteye.com/production/res/rxjg.js?pkcgstj=jm"></script></div>
    

    <div class="recommend-item-box recommend-recommend-box"><div id="_pu1jnucpsw9" style=""><div class="fjwsmijgielx" style="display:none;"></div><iframe width="852" frameborder="0" height="60" scrolling="no" src="https://pos.baidu.com/s?hei=60&amp;wid=852&amp;di=u3491668&amp;ltu=https%3A%2F%2Fblog.csdn.net%2Fguyongqiangx%2Farticle%2Fdetails%2F71334889&amp;psi=bb3c0f51e5fca292318a56f3a60b26d7&amp;dc=3&amp;dis=0&amp;pis=-1x-1&amp;ari=2&amp;ti=Android%20A%2FB%20System%20OTA%E5%88%86%E6%9E%90%EF%BC%88%E4%B8%80%EF%BC%89%E6%A6%82%E8%A7%88&amp;cfv=0&amp;tpr=1571407096295&amp;col=zh-CN&amp;cec=UTF-8&amp;par=1366x720&amp;ccd=24&amp;dtm=HTML_POST&amp;exps=111000,110011&amp;tlm=1571407096&amp;cdo=-1&amp;ant=0&amp;cja=false&amp;cmi=39&amp;dri=2&amp;chi=50&amp;ps=10737x378&amp;dai=8&amp;tcn=1571407096&amp;drs=1&amp;psr=1366x768&amp;prot=2&amp;cce=true&amp;pss=1345x10790&amp;pcs=1345x587&amp;cpl=21"></iframe></div><script type="text/javascript" src="//rabc1.iteye.com/production/res/rxjg.js?pkcgstj=jm"></script></div>
    

                <div class="recommend-item-box type_hot_word">
                                <div class="content clearfix" style="width: 852px;">
                    <div class="float-left">
                                        <span>
                        <a href="https://www.csdn.net/gather_13/MtTaAgxsLWRvd25sb2Fk.html" target="_blank">
                        c#可被js调用的函数</a>
                    </span>
                                        <span>
                        <a href="https://www.csdn.net/gather_1e/MtTaAgysLWRvd25sb2Fk.html" target="_blank">
                        c# 日志文件</a>
                    </span>
                                        <span>
                        <a href="https://www.csdn.net/gather_16/MtTaAgzsLWRvd25sb2Fk.html" target="_blank">
                        c# mvc中间件</a>
                    </span>
                                        <span>
                        <a href="https://www.csdn.net/gather_1c/MtTaAg0sLWRvd25sb2Fk.html" target="_blank">
                        c#爬虫路径中文件名过长</a>
                    </span>
                                        <span>
                        <a href="https://www.csdn.net/gather_16/MtTaAg1sLWRvd25sb2Fk.html" target="_blank">
                        c# mutex 延时</a>
                    </span>
                                        <span>
                        <a href="https://www.csdn.net/gather_1f/MtTaAg2sLWRvd25sb2Fk.html" target="_blank">
                        c# mysql 功能码</a>
                    </span>
                                        <span>
                        <a href="https://www.csdn.net/gather_1a/MtTaAg3sLWRvd25sb2Fk.html" target="_blank">
                        c# 多态 封装</a>
                    </span>
                                        <span>
                        <a href="https://www.csdn.net/gather_1a/MtTaAg4sLWRvd25sb2Fk.html" target="_blank">
                        c# 校园一卡通接口</a>
                    </span>
                                        <span>
                        <a href="https://www.csdn.net/gather_12/MtTaAg5sLWRvd25sb2Fk.html" target="_blank">
                        c#本地帮助文档</a>
                    </span>
                                        <span>
                        <a href="https://www.csdn.net/gather_15/MtTaEgwsLWRvd25sb2Fk.html" target="_blank">
                        c#两个table左联接</a>
                    </span>
                                        </div>
                </div>
                                </div>
                            <div class="recommend-loading-box">
                <img src="https://csdnimg.cn/release/phoenix/images/feedLoading.gif">
            </div>
            <div class="recommend-end-box" style="display: block;">
                <p class="text-center">没有更多推荐了,<a href="https://blog.csdn.net/" class="c-blue c-blue-hover c-blue-focus">返回首页</a></p>
            </div>
        </div>
                    <div class="template-box">
                <span>©️2019 CSDN</span><span class="point"></span>
            <span>皮肤主题: 编程工作室</span>
            <span> 设计师:
                                    CSDN官方博客                            </span>
            </div>
            </main>
    
    posted @ 2019-10-18 21:40  SlamDunk_1016  阅读(1011)  评论(0)    收藏  举报