<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:media="http://search.yahoo.com/mrss/"><channel><title><![CDATA[Shunix's Weblog]]></title><description><![CDATA[Everything I've done has made me who I am today.]]></description><link>https://shunix.com/</link><image><url>https://shunix.com/favicon.png</url><title>Shunix&apos;s Weblog</title><link>https://shunix.com/</link></image><generator>Ghost 4.7</generator><lastBuildDate>Thu, 16 Apr 2026 01:25:16 GMT</lastBuildDate><atom:link href="https://shunix.com/rss/" rel="self" type="application/rss+xml"/><ttl>60</ttl><item><title><![CDATA[深入应用冷启动优化]]></title><description><![CDATA[<!--kg-card-begin: markdown--><h1 id>&#x80CC;&#x666F;</h1>
<h2 id>&#x4E3A;&#x4EC0;&#x4E48;&#x505A;&#x51B7;&#x542F;&#x52A8;&#x4F18;&#x5316;</h2>
<p>&#x51B7;&#x542F;&#x52A8;&#x65F6;&#x95F4;&#x662F;&#x7528;&#x6237;&#x5BF9;app&#x7684;&#x7B2C;&#x4E00;&#x5370;&#x8C61;&#xFF0C;&#x7EBF;&#x4E0A;AB&#x5B9E;&#x9A8C;&#x8868;&#x660E;&#xFF0C;&#x51B7;&#x542F;&#x52A8;&#x65F6;&#x95F4;&#x4F1A;&#x76F4;&#x63A5;&#x5F71;&#x54CD;&#x7528;&#x6237;&#x7684;&#x7559;&#x5B58;</p>]]></description><link>https://shunix.com/launch-optimization/</link><guid isPermaLink="false">60812ae62b3f873b19511eca</guid><category><![CDATA[技术文章]]></category><dc:creator><![CDATA[Shunix]]></dc:creator><pubDate>Thu, 01 Oct 2020 06:17:00 GMT</pubDate><content:encoded><![CDATA[<!--kg-card-begin: markdown--><h1 id>&#x80CC;&#x666F;</h1>
<h2 id>&#x4E3A;&#x4EC0;&#x4E48;&#x505A;&#x51B7;&#x542F;&#x52A8;&#x4F18;&#x5316;</h2>
<p>&#x51B7;&#x542F;&#x52A8;&#x65F6;&#x95F4;&#x662F;&#x7528;&#x6237;&#x5BF9;app&#x7684;&#x7B2C;&#x4E00;&#x5370;&#x8C61;&#xFF0C;&#x7EBF;&#x4E0A;AB&#x5B9E;&#x9A8C;&#x8868;&#x660E;&#xFF0C;&#x51B7;&#x542F;&#x52A8;&#x65F6;&#x95F4;&#x4F1A;&#x76F4;&#x63A5;&#x5F71;&#x54CD;&#x7528;&#x6237;&#x7684;&#x7559;&#x5B58;&#x3002;</p>
<h2 id>&#x51B7;&#x542F;&#x52A8;&#x65F6;&#x95F4;&#x53E3;&#x5F84;</h2>
<p>&#x8D77;&#x70B9;&#xFF1A;Application#attachBaseContext()<br>
&#x7ED3;&#x675F;&#x65F6;&#x95F4;&#xFF1A;&#x7B2C;&#x4E00;&#x4E2A;Activity&#x7684;onWindowFocusChanged()<br>
&#x4E3A;&#x4EC0;&#x4E48;&#x662F;&#x8FD9;&#x4E24;&#x4E2A;&#x70B9;&#xFF1F;Application#attachBaseContext()&#x662F;&#x5E94;&#x7528;&#x4EE3;&#x7801;&#x88AB;&#x6267;&#x884C;&#x7684;&#x6700;&#x65E9;&#x8282;&#x70B9;&#xFF0C;&#x7B2C;&#x4E00;&#x4E2A;Activity&#x7684;onWindowFocusChanged()&#x662F;&#x7B2C;&#x4E00;&#x5E27;&#x5B8C;&#x6210;&#x7ED8;&#x5236;&#x7684;&#x65F6;&#x95F4;&#x3002;<br>
&#x8FD9;&#x91CC;&#x6709;&#x4E00;&#x4E2A;&#x5C0F;&#x5751;&#xFF0C;&#x4E4B;&#x524D;Launcher Activity&#x8FD8;&#x662F;SplashActivity&#x7684;&#x65F6;&#x5019;&#xFF0C;&#x6211;&#x4EEC;&#x53D1;&#x73B0;SplashActivity&#x7684;onWindowFocusChanged()&#x6C38;&#x8FDC;&#x4E0D;&#x4F1A;&#x88AB;&#x6267;&#x884C;&#xFF0C;&#x56E0;&#x4E3A;&#x8FD8;&#x6CA1;&#x6267;&#x884C;&#x5230;onWindowFocusChanged()&#x65F6;&#xFF0C;SplashActivity&#x5C31;finish&#x4E86;&#xFF0C;&#x56E0;&#x6B64;&#x6211;&#x4EEC;&#x7684;&#x51B7;&#x542F;&#x52A8;&#x4E0A;&#x62A5;&#x505A;&#x5728;&#x4E86;MainActivity&#x7684;onWindowFocusChanged()&#x91CC;&#xFF0C;&#x8FD9;&#x4E5F;&#x5BFC;&#x81F4;&#x4E86;&#x4E4B;&#x524D;&#x7248;&#x672C;&#x7EBF;&#x4E0A;&#x6570;&#x636E;&#x504F;&#x9AD8;&#x3002;</p>
<h2 id>&#x533A;&#x5206;&#x51B7;&#x542F;&#x52A8;</h2>
<p>&#x9996;&#x5148;&#x6211;&#x4EEC;&#x6765;&#x5B9A;&#x4E49;&#x4E00;&#x4E0B;&#x51B7;&#x542F;&#x52A8;&#xFF0C;&#x51B7;&#x542F;&#x52A8;&#x6307;&#x7684;&#x662F;&#x7CFB;&#x7EDF;&#x4E0D;&#x5B58;&#x5728;&#x5E94;&#x7528;&#x8FDB;&#x7A0B;&#x7684;&#x60C5;&#x51B5;&#x4E0B;&#xFF0C;&#x542F;&#x52A8;&#x5E94;&#x7528;&#x3002;&#x5982;&#x679C;&#x6211;&#x4EEC;&#x53EA;&#x5728;SplashActivity&#x6216;&#x8005;MainActivity&#x7B2C;&#x4E00;&#x6B21;&#x521B;&#x5EFA;&#x65F6;&#x4E0A;&#x62A5;&#xFF0C;&#x4EE5;&#x4E0B;&#x51E0;&#x4E2A;&#x573A;&#x666F;&#x4F1A;&#x88AB;&#x8BEF;&#x62A5;&#x6210;&#x51B7;&#x542F;&#x52A8;&#xFF1A;</p>
<ol>
<li>&#x5E94;&#x7528;&#x63A5;&#x6536;&#x5230;&#x5E7F;&#x64AD;&#xFF0C;&#x62C9;&#x8D77;&#x4E86;&#x4E3B;&#x8FDB;&#x7A0B;&#xFF0C;&#x4E4B;&#x540E;&#x518D;&#x70B9;&#x51FB;&#x684C;&#x9762;&#x56FE;&#x6807;&#x8FDB;&#x5165;</li>
<li>&#x4E3B;&#x8FDB;&#x7A0B;&#x901A;&#x8FC7;ContentProvider&#x88AB;&#x62C9;&#x8D77;&#xFF0C;&#x4E4B;&#x540E;&#x518D;&#x70B9;&#x51FB;&#x684C;&#x9762;&#x56FE;&#x6807;&#x8FDB;&#x5165;</li>
<li>&#x901A;&#x8FC7;&#x70B9;&#x51FB;push&#x8FDB;&#x5230;&#x4E86;&#x4E00;&#x4E2A;&#x843D;&#x5730;&#x9875;&#xFF0C;&#x6309;&#x8FD4;&#x56DE;&#x952E;&#x9000;&#x51FA;&#x540E;&#xFF0C;&#x518D;&#x70B9;&#x51FB;&#x684C;&#x9762;&#x56FE;&#x6807;&#x8FDB;&#x5165;</li>
</ol>
<p>&#x8981;&#x628A;&#x51B7;&#x542F;&#x548C;&#x975E;&#x51B7;&#x542F;&#x6700;&#x5173;&#x952E;&#x7684;&#x5DEE;&#x522B;&#xFF0C;&#x5C31;&#x5728;&#x4E8E;Application&#x662F;&#x5426;&#x9700;&#x8981;&#x521B;&#x5EFA;&#x3002;&#x76EE;&#x524D;&#x4E3B;&#x7AEF;&#x7684;&#x505A;&#x6CD5;&#x662F;&#xFF0C;&#x5728;Application#onCreate()&#x7ED3;&#x675F;&#x65F6;&#xFF0C;&#x8BB0;&#x4E00;&#x4E2A;&#x65F6;&#x95F4;ts1&#xFF0C;&#x5728;Launcher Activity#onCreate()&#x5F00;&#x59CB;&#x65F6;&#x518D;&#x8BB0;&#x4E00;&#x4E2A;&#x65F6;&#x95F4;ts2&#xFF0C;&#x5982;&#x679C;ts2 - ts1 &lt; 200ms&#xFF0C;&#x5C31;&#x8BA4;&#x4E3A;&#x662F;&#x51B7;&#x542F;&#x52A8;&#x3002;&#x5728;&#x5927;&#x90E8;&#x5206;&#x60C5;&#x51B5;&#x4E0B;&#xFF0C;&#x8FD9;&#x4E2A;&#x5224;&#x65AD;&#x90FD;&#x662F;&#x51C6;&#x786E;&#x7684;&#xFF0C;&#x4E00;&#x5B9A;&#x4E0D;&#x4F1A;&#x51FA;&#x73B0;&#x8BEF;&#x62A5;&#xFF0C;&#x4F46;&#x662F;&#x901A;&#x8FC7;&#x70B9;&#x51FB;push&#x8FDB;&#x843D;&#x5730;&#x9875;&#x7684;&#x60C5;&#x51B5;&#xFF0C;&#x5982;&#x679C;&#x8FDB;&#x7A0B;&#x4E0D;&#x5B58;&#x5728;&#x4E5F;&#x7B97;&#x51B7;&#x542F;&#x52A8;&#xFF0C;&#x4F1A;&#x6F0F;&#x62A5;&#x3002;<br>
&#x90A3;&#x4E48;&#x6709;&#x6CA1;&#x6709;&#x4E00;&#x4E2A;&#x5B8C;&#x7F8E;&#x7684;&#x89E3;&#x51B3;&#x65B9;&#x6848;&#x5462;&#xFF1F;&#x6211;&#x4EEC;&#x5148;&#x770B;&#x4E00;&#x5F20;&#x5E94;&#x7528;&#x51B7;&#x542F;&#x52A8;&#x7684;&#x65F6;&#x5E8F;&#x56FE;&#xFF1A;<br>
<img src="https://github.com/shunix/BlogImages/blob/master/20200930_app_launch_timeline.png?raw=true" alt="Timeline" loading="lazy"><br>
&#x6211;&#x4EEC;&#x77E5;&#x9053;&#xFF0C;&#x8FD9;&#x91CC;&#x7684;&#x6D88;&#x606F;&#x90FD;&#x4F1A;&#x88AB;&#x5206;&#x53D1;&#x5230;ActivityThread&#x7684;Handler&#x4E0A;&#x5904;&#x7406;&#xFF0C;&#x5173;&#x6CE8;&#x4E24;&#x4E2A;&#x6D88;&#x606F;&#xFF0C;BIND_APPLICATION&#x548C;EXECUTE_TRANSACTION&#xFF0C;&#x5904;&#x7406;BIND_APPLICATION&#x6D88;&#x606F;&#x65F6;&#xFF0C;&#x4F1A;&#x8C03;&#x7528;Application#onCreate()&#x65B9;&#x6CD5;&#xFF0C;&#x800C;&#x8FD9;&#x4E2A;&#x65F6;&#x5019;&#xFF0C;&#x6D88;&#x606F;&#x961F;&#x5217;&#x4E2D;&#x5DF2;&#x7ECF;&#x6709;&#x4E86;EXECUTE_TRANSACTION&#x6D88;&#x606F;&#xFF0C;&#x5904;&#x7406;EXECUTE_TRANSACTION&#x6D88;&#x606F;&#x4F1A;&#x521B;&#x5EFA;Activity&#xFF0C;&#x8D70;Activity&#x7684;&#x751F;&#x547D;&#x5468;&#x671F;&#x3002;&#x6240;&#x4EE5;&#x53EA;&#x9700;&#x8981;&#x5728;Application#onCreate()&#x65B9;&#x6CD5;&#x4E2D;post&#x4E00;&#x4E2A;&#x6D88;&#x606F;&#x5230;&#x4E3B;&#x7EBF;&#x7A0B;&#xFF0C;&#x5728;&#x8FD9;&#x4E2A;&#x6D88;&#x606F;&#x4E2D;&#x68C0;&#x6D4B;&#xFF0C;&#x5982;&#x679C;&#x5DF2;&#x7ECF;&#x6709;Activity&#x521B;&#x5EFA;&#x8FC7;&#xFF0C;&#x90A3;&#x4E48;&#x5C31;&#x8BA4;&#x4E3A;&#x8FD9;&#x662F;&#x51B7;&#x542F;&#x52A8;&#xFF0C;&#x524D;&#x9762;&#x8BF4;&#x7684;&#x51E0;&#x79CD;&#x60C5;&#x51B5;&#xFF1A;</p>
<ol>
<li>&#x5E7F;&#x64AD;&#x5BFC;&#x81F4;&#x7684;&#x8FDB;&#x7A0B;&#x88AB;&#x62C9;&#x8D77;&#xFF0C;&#x56E0;&#x4E3A;&#x6CA1;&#x6709;&#x521B;&#x5EFA;Activity&#xFF0C;&#x56E0;&#x6B64;&#x4E0D;&#x4F1A;&#x4E0A;&#x62A5;&#x51B7;&#x542F;&#x52A8;</li>
<li>Content Provider&#x5BFC;&#x81F4;&#x7684;&#x8FDB;&#x7A0B;&#x62C9;&#x8D77;&#x540C;&#x4E0A;</li>
<li>&#x70B9;&#x51FB;push&#x8FDB;&#x843D;&#x5730;&#x9875;&#x7684;&#x6F0F;&#x62A5;&#xFF0C;&#x8FD9;&#x4E2A;&#x65B9;&#x6848;&#x4E5F;&#x80FD;&#x89E3;&#x51B3;&#x3002;</li>
</ol>
<p>&#x793A;&#x4F8B;&#x4EE3;&#x7801;&#xFF1A;</p>
<pre><code>class MyApp : Application() {

  override fun onCreate() {
    super.onCreate()

    var firstActivityCreated = false

    registerActivityLifecycleCallbacks(object :
        ActivityLifecycleCallbacks {

      override fun onActivityCreated(
          activity: Activity,
          savedInstanceState: Bundle?
      ) {
        if (firstActivityCreated) {
          return
        }
        firstActivityCreated = true
      }
    })
    Handler().post {
      if (firstActivityCreated) {
        // &#x4E0A;&#x62A5;&#x51B7;&#x542F;&#x52A8;
      }
    }
  }}
</code></pre>
<h2 id>&#x8BEF;&#x533A;</h2>
<p>&#x5F88;&#x591A;&#x9879;&#x76EE;&#x90FD;&#x505A;&#x8FC7;&#x542F;&#x52A8;&#x4F18;&#x5316;&#xFF0C;&#x5927;&#x90E8;&#x5206;&#x90FD;&#x7ECF;&#x5386;&#x8FC7;&#x5982;&#x4E0B;&#x9636;&#x6BB5;&#xFF1A;</p>
<ol>
<li>&#x91CE;&#x86EE;&#x751F;&#x957F;&#x9636;&#x6BB5;&#xFF0C;&#x5927;&#x91CF;&#x903B;&#x8F91;&#x5199;&#x5728;Application#onCreate()&#x4E2D;&#xFF0C;&#x542F;&#x52A8;&#x9636;&#x6BB5;&#x4E32;&#x884C;&#x6267;&#x884C;</li>
<li>&#x610F;&#x8BC6;&#x5230;&#x95EE;&#x9898;&#xFF0C;&#x5F00;&#x59CB;&#x505A;&#x542F;&#x52A8;&#x9636;&#x6BB5;&#x4EFB;&#x52A1;&#x89E3;&#x8026;&#xFF0C;&#x5F02;&#x6B65;&#x6267;&#x884C;&#x90E8;&#x5206;&#x4EFB;&#x52A1;</li>
<li>&#x5F15;&#x5165;&#x542F;&#x52A8;&#x4EFB;&#x52A1;&#x8C03;&#x5EA6;&#x6846;&#x67B6;&#xFF0C;&#x89E3;&#x51B3;&#x5F02;&#x6B65;&#x4EFB;&#x52A1;&#x7684;&#x65F6;&#x5E8F;&#x548C;&#x4F9D;&#x8D56;&#x95EE;&#x9898;<br>
&#x5F88;&#x591A;&#x9879;&#x76EE;&#x505A;&#x5230;&#x8FD9;&#x91CC;&#x5C31;&#x7ED3;&#x675F;&#x4E86;&#xFF0C;&#x5728;&#x5F88;&#x591A;&#x4EBA;&#x7684;&#x7406;&#x89E3;&#x4E2D;&#xFF0C;&#x9AD8;&#x5EA6;&#x5F02;&#x6B65; == &#x603B;&#x65F6;&#x95F4;&#x6700;&#x77ED;&#x3002;&#x8FD9;&#x662F;&#x4E00;&#x4E2A;&#x60F3;&#x5F53;&#x7136;&#x7684;&#x7ED3;&#x8BBA;&#xFF0C;&#x9AD8;&#x5EA6;&#x5F02;&#x6B65;&#x5316;&#x4E4B;&#x540E;&#x4F9D;&#x7136;&#x6709;&#x4E0D;&#x5C11;&#x53EF;&#x6539;&#x8FDB;&#x7684;&#x7A7A;&#x95F4;&#x3002;</li>
</ol>
<h1 id>&#x53D1;&#x73B0;&#x95EE;&#x9898;</h1>
<p>&#x4ECE;&#x4EE3;&#x7801;&#x4E0A;&#x6765;&#x770B;&#xFF0C;&#x542F;&#x52A8;&#x4EFB;&#x52A1;&#x5DF2;&#x7ECF;&#x505A;&#x5230;&#x4E86;&#x9AD8;&#x5EA6;&#x5E76;&#x884C;&#xFF0C;&#x5F88;&#x96BE;&#x627E;&#x5230;&#x4E00;&#x4E9B;&#x7B80;&#x5355;&#x53C8;&#x89C1;&#x6548;&#x5FEB;&#x7684;&#x624B;&#x6BB5;&#xFF0C;&#x56E0;&#x6B64;&#x9700;&#x8981;&#x5BF9;&#x542F;&#x52A8;&#x8FC7;&#x7A0B;&#x505A;&#x7C92;&#x5EA6;&#x66F4;&#x5C0F;&#x7684;&#x7EC6;&#x5206;&#xFF0C;&#x627E;&#x5230;&#x53EF;&#x80FD;&#x7684;&#x4F18;&#x5316;&#x70B9;&#x3002;&#x8FD9;&#x91CC;&#x4F7F;&#x7528;&#x4E86;systrace&#x5DE5;&#x5177;&#x6765;&#x5206;&#x6790;&#x542F;&#x52A8;&#x9636;&#x6BB5;&#x3002;</p>
<h2 id="systrace">&#x4E3A;&#x4EC0;&#x4E48;&#x7528;systrace</h2>
<p>&#x76F8;&#x6BD4;&#x7EBF;&#x4E0A;&#x76D1;&#x63A7;&#x7528;&#x7684;&#x57CB;&#x70B9;&#xFF0C;&#x65E5;&#x5FD7;&#x7B49;&#x65B9;&#x6CD5;&#xFF0C;&#x7EBF;&#x4E0B;&#x5206;&#x6790;&#x4F7F;&#x7528;systrace&#x80FD;&#x83B7;&#x5F97;&#x66F4;&#x5168;&#x9762;&#x7684;&#x4FE1;&#x606F;&#x3002;systrace&#x63D0;&#x4F9B;&#x4E86;&#x5168;&#x5C40;&#x7684;&#x89C6;&#x89D2;&#xFF0C;&#x80FD;&#x6E05;&#x695A;&#x7684;&#x770B;&#x5230;CPU&#x5F53;&#x524D;&#x8D1F;&#x8F7D;&#x4EE5;&#x53CA;&#x8C03;&#x5EA6;&#x60C5;&#x51B5;&#xFF0C;&#x6BD4;&#x5982;&#x4E0B;&#x9762;&#x8FD9;&#x4E2A;case&#xFF1A;<br>
<img src="https://github.com/shunix/BlogImages/blob/master/20200930_init_trace_1.png?raw=true" alt="init_trace_1" loading="lazy"><br>
&#x8FD9;&#x4E2A;&#x542F;&#x52A8;&#x4EFB;&#x52A1;&#x7684;Wall Duration&#x6709;112ms&#xFF0C;&#x5982;&#x679C;&#x901A;&#x8FC7;&#x6253;&#x65E5;&#x5FD7;&#x7684;&#x65B9;&#x5F0F;&#xFF0C;&#x6211;&#x4EEC;&#x5F97;&#x5230;&#x7684;&#x7ED3;&#x8BBA;&#x5C31;&#x662F;&#x8FD9;&#x4E2A;&#x4EFB;&#x52A1;&#x8017;&#x65F6;&#x8FC7;&#x957F;&#xFF0C;&#x4F46;&#x662F;&#x4ECE;systrace&#x4E0A;&#xFF0C;&#x6211;&#x4EEC;&#x770B;&#x5230;CPU Duration&#x53EA;&#x6709;18ms&#xFF0C;&#x771F;&#x6B63;&#x5360;&#x7528;&#x4E86;&#x5F88;&#x591A;&#x65F6;&#x95F4;&#x7684;&#xFF0C;&#x662F;&#x591A;&#x6B21;&#x9501;&#x7684;&#x7ADE;&#x7528;&#x3002;<br>
&#x56E0;&#x6B64;&#x8FD9;&#x4E2A;&#x4EFB;&#x52A1;&#x4F18;&#x5316;&#x7684;&#x91CD;&#x70B9;&#x5E94;&#x8BE5;&#x662F;&#x89E3;&#x51B3;&#x9501;&#x7ADE;&#x7528;&#x7684;&#x95EE;&#x9898;&#xFF0C;&#x5982;&#x679C;&#x7528;&#x6253;&#x65E5;&#x5FD7;&#x7684;&#x65B9;&#x5F0F;&#xFF0C;&#x53EA;&#x80FD;&#x770B;&#x5230;&#x8868;&#x9762;&#x73B0;&#x8C61;&#xFF0C;&#x5F88;&#x5BB9;&#x6613;&#x628A;&#x4F18;&#x5316;&#x65B9;&#x5411;&#x5E26;&#x504F;&#x4E86;&#x3002;<br>
&#x5982;&#x679C;&#x662F;&#x8FC7;&#x5EA6;&#x5E76;&#x884C;&#xFF0C;&#x5BFC;&#x81F4;&#x5F88;&#x591A;&#x4EFB;&#x52A1;&#x5728;Runnable&#x7684;&#x72B6;&#x6001;&#x7B49;&#x5F85;CPU&#x65F6;&#x95F4;&#x7247;&#xFF0C;&#x8FD9;&#x79CD;&#x60C5;&#x51B5;&#x901A;&#x8FC7;&#x65E5;&#x5FD7;&#x4E5F;&#x4F1A;&#x5F97;&#x51FA;&#x9519;&#x8BEF;&#x7684;&#x4FE1;&#x606F;&#xFF0C;&#x7EBF;&#x4E0B;&#x5206;&#x6790;&#x8FD8;&#x662F;&#x5EFA;&#x8BAE;&#x7528;systrace&#x3002;</p>
<h2 id="releasesystrace">&#x6253;&#x5F00;release systrace</h2>
<p>&#x770B;systrace&#x5EFA;&#x8BAE;&#x4F7F;&#x7528;release&#x5305;&#xFF0C;debug&#x5305;&#x7684;&#x5F88;&#x591A;&#x884C;&#x4E3A;&#x548C;release&#x5305;&#x4E0D;&#x4E00;&#x6837;&#xFF0C;&#x4E00;&#x4E9B;&#x6B65;&#x9AA4;&#x7684;&#x8017;&#x65F6;&#x4E5F;&#x5F88;&#x4E0D;&#x4E00;&#x6837;&#xFF0C;debug&#x5305;&#x5F97;&#x51FA;&#x7684;&#x4E00;&#x4E9B;&#x7ED3;&#x8BBA;&#x65E0;&#x6CD5;&#x5E73;&#x79FB;&#x5230;release&#x5305;&#xFF0C;&#x6BD4;&#x5982;debug&#x5305;dex&#x52A0;&#x8F7D;&#x65F6;&#x95F4;&#x4F1A;&#x7279;&#x522B;&#x957F;&#xFF0C;release&#x6CA1;&#x6709;&#x8FD9;&#x4E2A;&#x95EE;&#x9898;&#xFF0C;&#x4F18;&#x5316;dex&#x7684;ROI&#x5C31;&#x5F88;&#x4F4E;&#x3002;<br>
release&#x5305;&#x9ED8;&#x8BA4;&#x662F;&#x5173;&#x95ED;&#x4E86;systrace&#x7684;&#xFF0C;&#x5728;ActivityThread&#x91CC;&#x6709;&#x8FD9;&#x4E48;&#x4E00;&#x6BB5;&#xFF1A;</p>
<pre><code>// Allow application-generated systrace messages if we&apos;re debuggable 
boolean isAppDebuggable = (data.appInfo.flags &amp; ApplicationInfo.FLAG_DEBUGGABLE) != 0; 
Trace.setAppTracingAllowed(isAppDebuggable);
</code></pre>
<p>&#x518D;&#x770B;&#x770B;Trace&#x7C7B;&#xFF1A;</p>
<pre><code>/**
* Set whether tracing is enabled in this process.  Tracing is disabled shortly after Zygote
* initializes and re-enabled after processes fork from Zygote.  This is done because Zygote
* has no way to be notified about changes to the tracing tags, and if Zygote ever reads and
* caches the tracing tags, forked processes will inherit those stale tags.
*
* @hide
*/
public static void setTracingEnabled(boolean enabled, int debugFlags) {
    nativeSetTracingEnabled(enabled);
    sZygoteDebugFlags = debugFlags;

    // Setting whether tracing is enabled may change the tags, so we update the cached tags
    // here.
    cacheEnabledTags();
}
</code></pre>
<p>&#x6CA1;&#x6709;&#x4EC0;&#x4E48;&#x5751;&#xFF0C;&#x53EA;&#x9700;&#x8981;&#x5728;Application#attachBaseContext&#x53CD;&#x5C04;&#x8C03;&#x7528;&#x8FD9;&#x4E2A;&#x65B9;&#x6CD5;&#xFF0C;&#x5C31;&#x53EF;&#x4EE5;&#x6253;&#x5F00;release&#x5305;&#x7684;systrace&#x3002;&#x9644;&#x4E0A;&#x4E00;&#x4E2A;&#x5DE5;&#x5177;&#x65B9;&#x6CD5;&#xFF1A;</p>
<pre><code>fun enableReleaseTrace() {
    try {
     Class.forName(&quot;android.os.Trace&quot;).getDeclaredMethod(&quot;setAppTracingAllowed&quot;, Boolean::class.java).invoke(null, true)
    } catch (tr: Throwable) {
        Log.e(TAG, Log.getStackTraceString(tr))
    }
}
</code></pre>
<h2 id>&#x5206;&#x6790;&#x73B0;&#x72B6;</h2>
<p>&#x4E0B;&#x9762;&#x8FD9;&#x5F20;&#x56FE;&#x662F;&#x4F18;&#x5316;&#x524D;&#x7684;trace&#xFF0C;&#x53EA;&#x770B;&#x4E3B;&#x7EBF;&#x7A0B;&#x8FD9;&#x6839;&#x7EBF;&#xFF0C;&#x57FA;&#x672C;&#x4E0A;&#x90FD;&#x662F;&#x7EFF;&#x8272;&#x7684;&#xFF0C;&#x4F46;&#x662F;CPU&#x5B58;&#x5728;&#x4E24;&#x5757;&#x533A;&#x57DF;&#x6709;&#x5927;&#x91CF;&#x7A7A;&#x767D;&#x7684;&#x65F6;&#x95F4;&#x7247;&#xFF0C;&#x5206;&#x522B;&#x5BF9;&#x5E94;&#x7684;Application#attachBaseContext()&#x4E4B;&#x524D;&#xFF0C;Application#attachBaseContext()&#x548C;Application#onCreate()&#x4E4B;&#x95F4;&#x7684;&#x65F6;&#x95F4;&#x3002;&#x8FD9;&#x4E24;&#x4E2A;&#x65F6;&#x95F4;&#x7247;&#x91CC;&#xFF0C;&#x53EA;&#x6709;&#x4E3B;&#x7EBF;&#x7A0B;&#x5728;&#x8DD1;&#xFF0C;&#x6CA1;&#x6709;&#x5229;&#x7528;&#x597D;CPU&#x3002;&#x542F;&#x52A8;&#x4F18;&#x5316;&#x7684;&#x672C;&#x8D28;&#xFF0C;&#x5C31;&#x662F;&#x628A;CPU&#x6253;&#x6EE1;&#x3002;<br>
<img src="https://github.com/shunix/BlogImages/blob/master/20200930_init_trace_2.png?raw=true" alt="init_trace_2" loading="lazy"><br>
&#x5728;ApplicationonCreate()&#x4E4B;&#x540E;&#xFF0C;&#x6709;&#x4E24;&#x4E2A;TransactionExecutor.execute&#x7684;tag&#xFF0C;&#x8BF4;&#x660E;&#x542F;&#x52A8;&#x4E86;&#x4E24;&#x4E2A;Activity&#xFF0C;&#x4F4E;&#x7AEF;&#x673A;&#x4E0A;&#x521B;&#x5EFA;Activity&#x6253;&#x6765;&#x7684;&#x5F00;&#x9500;&#x975E;&#x5E38;&#x660E;&#x663E;&#xFF1A;<br>
<img src="https://github.com/shunix/BlogImages/blob/master/20200930_init_trace_3.png?raw=true" alt="init_trace_3" loading="lazy"><br>
&#x7136;&#x540E;&#x8FD8;&#x662F;&#x4E0A;&#x9762;&#x8FD9;&#x5F20;&#x56FE;&#xFF0C;&#x5728;SplashActivity&#x7684;&#x521B;&#x5EFA;&#x8FC7;&#x7A0B;&#x4E2D;&#xFF0C;&#x51FA;&#x73B0;&#x4E86;&#x5927;&#x6BB5;&#x4E3B;&#x8FDB;&#x7A0B;&#x7684;&#x4E3B;&#x7EBF;&#x7A0B;&#x5728;Sleeping&#x7684;&#x60C5;&#x51B5;&#xFF0C;&#x4F46;&#x662F;&#x8FD9;&#x4E2A;&#x65F6;&#x5019;&#x5E76;&#x6CA1;&#x6709;&#x5176;&#x4ED6;&#x7EBF;&#x7A0B;&#x5728;&#x6267;&#x884C;&#x4EFB;&#x52A1;&#xFF0C;&#x6240;&#x4EE5;&#x6211;&#x4EEC;&#x8981;&#x4ECE;CPU&#x5165;&#x624B;&#x3002;&#x4E4B;&#x524D;&#x4E3B;&#x7EBF;&#x7A0B;&#x8FD0;&#x884C;&#x5728;CPU3&#x4E0A;&#xFF0C;&#x6211;&#x4EEC;&#x770B;&#x770B;CPU3&#x7684;&#x65F6;&#x95F4;&#x7247;&#x5206;&#x914D;&#x7ED9;&#x8C01;&#x4E86;&#xFF1A;<br>
<img src="https://github.com/shunix/BlogImages/blob/master/20200930_init_trace_4.png?raw=true" alt="init_trace_4" loading="lazy"><br>
&#x5927;&#x91CF;&#x7684;&#x65F6;&#x95F4;&#x7247;&#x5206;&#x7ED9;&#x4E86;&#x6211;&#x4EEC;&#x5E94;&#x7528;&#x7684;push&#x8FDB;&#x7A0B;&#xFF0C;&#x5BF9;&#x5E94;pid&#x4E3A;32729&#xFF0C;&#x52FE;&#x9009;&#x4E0A;32729&#xFF0C;&#x521A;&#x597D;&#x8FD9;&#x6BB5;&#x65F6;&#x95F4;&#x5728;&#x505A;Application&#x7684;&#x521B;&#x5EFA;&#xFF1A;<br>
<img src="https://github.com/shunix/BlogImages/blob/master/20200930_init_trace_5.png?raw=true" alt="init_trace_5" loading="lazy"><br>
&#x518D;&#x5F80;&#x540E;&#x5230;Activity#onResume()&#x4E4B;&#x524D;&#x7684;&#x9636;&#x6BB5;&#xFF1A;<br>
<img src="https://github.com/shunix/BlogImages/blob/master/20200930_init_trace_6.png?raw=true" alt="init_trace_6" loading="lazy"><br>
&#x5E03;&#x5C40;&#x7684;inflate&#x5360;&#x4E86;&#x5927;&#x90E8;&#x5206;&#x7684;&#x65F6;&#x95F4;&#xFF0C;&#x5176;&#x4E2D;&#x6700;&#x957F;&#x7684;&#x8FD9;&#x4E00;&#x6761;&#x5360;&#x7528;&#x4E86;234ms&#xFF0C;&#x4E5F;&#x662F;&#x4E00;&#x4E2A;&#x4F18;&#x5316;&#x6536;&#x76CA;&#x6BD4;&#x8F83;&#x5927;&#x7684;&#x5730;&#x65B9;&#x3002;</p>
<h1 id>&#x4F18;&#x5316;&#x624B;&#x6BB5;</h1>
<p>&#x660E;&#x786E;&#x4E86;&#x95EE;&#x9898;&#x4E4B;&#x540E;&#xFF0C;&#x4F18;&#x5316;&#x601D;&#x8DEF;&#x5C31;&#x5F88;&#x6E05;&#x6670;&#x4E86;&#xFF0C;&#x4F18;&#x5148;&#x89E3;&#x51B3;&#x4E0B;&#x9762;&#x51E0;&#x4E2A;&#x95EE;&#x9898;&#xFF1A;</p>
<ol>
<li>&#x6253;&#x6EE1;Application&#x521B;&#x5EFA;&#x9636;&#x6BB5;&#x7684;CPU&#xFF0C;&#x907F;&#x514D;&#x51FA;&#x73B0;&#x5927;&#x5757;&#x7A7A;&#x95F2;&#x65F6;&#x95F4;&#x7247;</li>
<li>&#x5408;&#x5E76;SplashActivity&#x548C;MainActivity</li>
<li>&#x542F;&#x52A8;&#x9636;&#x6BB5;&#x4E0D;&#x8981;&#x62C9;&#x8D77;&#x5B50;&#x8FDB;&#x7A0B;</li>
<li>&#x7F29;&#x77ED;&#x4E3B;&#x7EBF;&#x7A0B;inflate&#x65F6;&#x95F4;</li>
</ol>
<h2 id="applicationcpu">&#x6253;&#x6EE1;Application&#x521B;&#x5EFA;&#x9636;&#x6BB5;&#x7684;CPU</h2>
<p>&#x8FD9;&#x91CC;&#x8981;&#x5206;&#x4E24;&#x6B65;&#x6765;&#xFF0C;&#x5206;&#x522B;&#x89E3;&#x51B3;&#x6211;&#x4EEC;&#x524D;&#x9762;&#x53D1;&#x73B0;&#x7684;&#x4E24;&#x6BB5;&#x7A7A;&#x95F2;&#x65F6;&#x95F4;&#x7247;</p>
<h3 id="attachbasecontext">&#x5229;&#x7528;&#x597D;attachBaseContext()&#x524D;&#x7684;&#x65F6;&#x95F4;</h3>
<p>&#x4ECE;trace&#x4E2D;&#x53EF;&#x4EE5;&#x770B;&#x51FA;&#xFF0C;Application#attachBaseContext()&#x4E4B;&#x524D;&#x7684;&#x65F6;&#x95F4;&#xFF0C;&#x53EA;&#x6709;&#x4E3B;&#x7EBF;&#x7A0B;&#x5728;&#x6267;&#x884C;&#xFF0C;&#x56E0;&#x4E3A;&#x5728;&#x8C03;&#x7528;super.attachBaseContext()&#x4E4B;&#x524D;&#xFF0C;&#x8C03;&#x7528;getApplicationContext()&#x4F1A;&#x4E3A;&#x7A7A;&#xFF0C;&#x800C;&#x5F88;&#x591A;SDK&#x4EE5;&#x53CA;&#x4E1A;&#x52A1;&#x4EE3;&#x7801;&#x83B7;&#x53D6;Context&#x90FD;&#x662F;&#x8FD9;&#x4E48;&#x5199;&#x7684;&#xFF0C;&#x4E4B;&#x524D;&#x6211;&#x4EEC;&#x6240;&#x6709;&#x7684;&#x4EFB;&#x52A1;&#x90FD;&#x662F;&#x5728;&#x8C03;&#x7528;&#x4E86;super.onAttachBaseContext()&#x4E4B;&#x540E;&#x5F00;&#x59CB;&#x8C03;&#x5EA6;&#x7684;&#xFF0C;&#x786E;&#x5B9E;&#x7701;&#x4E8B;&#xFF0C;&#x4F46;&#x4E5F;&#x6D6A;&#x8D39;&#x4E86;&#x8FD9;&#x90E8;&#x5206;&#x7684;&#x65F6;&#x95F4;&#x7247;&#x3002;&#x6240;&#x4EE5;&#x8FD9;&#x91CC;&#x6211;&#x4EEC;&#x505A;&#x4E86;&#x4E2A;&#x5C0F;&#x6539;&#x52A8;&#xFF0C;&#x8986;&#x5199;&#x4E86;Application&#x7684;getApplicationContext()&#x65B9;&#x6CD5;</p>
<pre><code>override fun getApplicationContext(): Context {
    return this
}
</code></pre>
<p>&#x8FD9;&#x4E48;&#x6539;&#x4E4B;&#x540E;&#xFF0C;&#x5927;&#x90E8;&#x5206;&#x83B7;&#x53D6;Context&#x7684;&#x573A;&#x666F;&#x5C31;&#x6CA1;&#x6709;&#x95EE;&#x9898;&#x4E86;&#xFF0C;&#x4F46;&#x662F;&#x5982;&#x679C;&#x83B7;&#x53D6;&#x7684;&#x662F;baseContext&#xFF0C;&#x8FD8;&#x662F;&#x4F1A;&#x6709;&#x95EE;&#x9898;&#xFF0C;&#x5728;&#x8C03;&#x7528;super.onAttachBaseContext()&#x4E4B;&#x524D;&#xFF0C;ContextWrapper&#x7684;mBase&#x662F;&#x6CA1;&#x6709;&#x8D4B;&#x503C;&#x7684;&#x3002;&#x7528;&#x5230;mBase&#x7684;&#x5730;&#x65B9;&#x8FD8;&#x662F;&#x4F1A;&#x6302;&#x6389;&#xFF0C;&#x4E0D;&#x8FC7;&#x95EE;&#x9898;&#x4E0D;&#x5927;&#xFF0C;attachBaseContext&#x4E4B;&#x524D;&#x7684;&#x4E00;&#x5C0F;&#x6BB5;&#x65F6;&#x95F4;&#x4E0D;&#x7B97;&#x957F;&#xFF0C;&#x5728;&#x8FD9;&#x4E2A;&#x9636;&#x6BB5;&#x521D;&#x59CB;&#x5316;&#x4E5F;&#x4E0D;&#x662F;&#x6BCF;&#x4E2A;SDK&#x90FD;&#x80FD;&#x9002;&#x914D;&#xFF0C;&#x56E0;&#x6B64;&#x53EA;&#x9009;&#x4E86;&#x4E00;&#x5C0F;&#x90E8;&#x5206;&#x4EFB;&#x52A1;&#xFF0C;&#x5F3A;&#x5236;&#x6307;&#x5B9A;&#x5728;&#x8FD9;&#x4E2A;&#x9636;&#x6BB5;&#x6267;&#x884C;&#x3002;</p>
<h3 id="attachbasecontextoncreategap">&#x62B9;&#x9664;attachBaseContext()&#x7ED3;&#x675F;&#x5230;onCreate()&#x5F00;&#x59CB;&#x524D;&#x7684;gap</h3>
<p>attachBaseContext()&#x7ED3;&#x675F;&#x5230;onCreate()&#x5F00;&#x59CB;&#x524D;&#x8FD8;&#x6709;&#x4E00;&#x6BB5;&#x65F6;&#x95F4;&#xFF0C;&#x5728;&#x6211;&#x8FD9;&#x53F0;&#x624B;&#x673A;&#x4E0A;&#x5927;&#x6982;&#x662F;70ms&#x5DE6;&#x53F3;&#xFF0C;&#x8FD9;&#x6BB5;&#x65F6;&#x95F4;&#x53EA;&#x6709;&#x4E3B;&#x7EBF;&#x7A0B;&#x5728;&#x6267;&#x884C;&#x4EFB;&#x52A1;&#xFF0C;&#x5176;&#x4ED6;&#x7EBF;&#x7A0B;&#x65F6;&#x95F4;&#x7247;&#x90FD;&#x6D6A;&#x8D39;&#x6389;&#x4E86;&#x3002;<br>
&#x4E0A;&#x9762;&#x4E24;&#x6B65;&#x505A;&#x5B8C;&#x540E;&#xFF0C;CPU&#x5DF2;&#x7ECF;&#x6CA1;&#x6709;&#x660E;&#x663E;&#x7684;&#x5927;&#x7247;&#x7A7A;&#x95F2;&#xFF1A;<br>
<img src="https://github.com/shunix/BlogImages/blob/master/20200930_init_trace_7.png?raw=true" alt="init_trace_7" loading="lazy"></p>
<h2 id="activity">&#x5408;&#x5E76;Activity</h2>
<p>&#x9879;&#x76EE;&#x7684;SplashActivity&#x4EC5;&#x4EC5;&#x662F;&#x4E00;&#x4E2A;&#x5360;&#x4F4D;&#x7684;Activity&#xFF0C;&#x5F53;&#x65F6;&#x505A;&#x8FD9;&#x4E2A;&#x95EA;&#x5C4F;&#x9875;&#x662F;&#x8003;&#x8651;&#x5230;&#x540E;&#x7EED;&#x53EF;&#x80FD;&#x6709;&#x5F00;&#x5C4F;&#x5E7F;&#x544A;&#xFF0C;&#x8FD0;&#x8425;&#x6D3B;&#x52A8;&#x4E4B;&#x7C7B;&#x7684;&#xFF0C;&#x60F3;&#x4ECE;&#x4E00;&#x5F00;&#x59CB;&#x5C31;&#x628A;&#x5F00;&#x5C4F;&#x903B;&#x8F91;&#x548C;&#x4E3B;&#x9875;&#x9762;&#x5206;&#x5F00;&#xFF0C;&#x65B9;&#x4FBF;&#x8FED;&#x4EE3;&#x7EF4;&#x62A4;&#x3002;&#x73B0;&#x5728;&#x770B;&#x8D77;&#x6765;&#x662F;&#x6709;&#x70B9;&#x8FC7;&#x5EA6;&#x8BBE;&#x8BA1;&#x4E86;&#xFF0C;&#x73B0;&#x5728;&#x8FD9;&#x4E2A;SplashActivity&#x7684;&#x4F5C;&#x7528;&#x5C31;&#x662F;&#x5C55;&#x793A;&#x4E00;&#x4E2A;&#x5F00;&#x5C4F;&#x80CC;&#x666F;&#x56FE;&#xFF0C;&#x6CA1;&#x6709;&#x590D;&#x6742;&#x903B;&#x8F91;&#x3002;<br>
&#x7136;&#x800C;&#x542F;&#x52A8;&#x4E00;&#x4E2A;Activity&#x6D89;&#x53CA;&#x5230;&#x548C;AMS&#x7684;IPC&#xFF0C;&#x8D44;&#x6E90;&#x52A0;&#x8F7D;&#xFF0C;&#x89C6;&#x56FE;&#x521B;&#x5EFA;&#x7B49;&#xFF0C;&#x6574;&#x4F53;&#x8017;&#x65F6;&#x5728;&#x4F4E;&#x7AEF;&#x673A;&#x4E0A;&#x80FD;&#x6709;&#x4E00;&#x4E24;&#x767E;&#x6BEB;&#x79D2;&#xFF0C;&#x542F;&#x52A8;&#x8FC7;&#x7A0B;&#x7701;&#x6389;&#x4E00;&#x4E2A;Activity&#x6536;&#x76CA;&#x662F;&#x5F88;&#x53EF;&#x89C2;&#x7684;&#x3002;<br>
&#x56E0;&#x6B64;&#xFF0C;&#x6211;&#x4EEC;&#x7684;SplashActivity&#x4E3A;&#x6570;&#x4E0D;&#x591A;&#x7684;&#x51E0;&#x884C;&#x4EE3;&#x7801;&#x5C31;&#x6574;&#x5408;&#x8FDB;&#x4E86;MainActivity&#x3002;&#x51B7;&#x542F;&#x52A8;&#x65F6;&#x95F4;&#x5728;&#x6211;&#x8FD9;&#x53F0;&#x624B;&#x673A;&#x4E0A;&#x5927;&#x6982;&#x4E0B;&#x964D;&#x4E86;100+ms&#xFF0C;&#x6536;&#x76CA;&#x8FD8;&#x662F;&#x5F88;&#x53EF;&#x4EE5;&#x7684;&#x3002;</p>
<h2 id>&#x542F;&#x52A8;&#x9636;&#x6BB5;&#x4E0D;&#x62C9;&#x8D77;&#x5B50;&#x8FDB;&#x7A0B;</h2>
<p>&#x4ECE;&#x4E0A;&#x9762;&#x7684;trace&#x4E2D;&#xFF0C;&#x6211;&#x4EEC;&#x53EF;&#x4EE5;&#x770B;&#x5230;CPU&#x8D44;&#x6E90;&#x5E76;&#x4E0D;&#x4F1A;&#x56E0;&#x4E3A;&#x65B0;&#x8D77;&#x4E00;&#x4E2A;&#x8FDB;&#x7A0B;&#x800C;&#x53D8;&#x6210;&#x53CC;&#x4EFD;&#xFF0C;&#x542F;&#x52A8;&#x9636;&#x6BB5;&#x62C9;&#x5B50;&#x8FDB;&#x7A0B;&#x4E00;&#x5B9A;&#x4F1A;&#x5BFC;&#x81F4;&#x4E3B;&#x8FDB;&#x7A0B;&#x65F6;&#x95F4;&#x7247;&#x88AB;&#x62A2;&#x3002;&#x5F88;&#x591A;&#x9879;&#x76EE;&#x7684;Application&#x4E2D;&#x90FD;&#x4F1A;&#x6709;&#x5173;&#x4E8E;&#x8FDB;&#x7A0B;&#x7684;&#x5224;&#x65AD;&#xFF0C;&#x5982;&#x679C;&#x975E;&#x4E3B;&#x8FDB;&#x7A0B;&#xFF0C;&#x8DF3;&#x8FC7;&#x4E00;&#x4E9B;&#x903B;&#x8F91;&#xFF0C;&#x4F46;&#x8FD9;&#x90FD;&#x662F;&#x6CBB;&#x6807;&#x4E0D;&#x6CBB;&#x672C;&#x7684;&#x65B9;&#x6CD5;&#xFF0C;fork&#x8FDB;&#x7A0B;&#xFF0C;&#x52A0;&#x8F7D;&#x8D44;&#x6E90;&#xFF0C;&#x52A0;&#x8F7D;&#x7C7B;&#xFF0C;&#x8FD9;&#x4E9B;&#x90FD;&#x8981;CPU&#xFF0C;&#x8FD8;&#x4F1A;&#x9020;&#x6210;&#x4E00;&#x4E9B;IO&#x3002;&#x56E0;&#x6B64;&#x5728;&#x542F;&#x52A8;&#x9636;&#x6BB5;&#x6700;&#x597D;&#x4E0D;&#x8981;&#x62C9;&#x8D77;&#x5B50;&#x8FDB;&#x7A0B;&#x3002;&#x7ECF;&#x8FC7;&#x8BC4;&#x4F30;&#xFF0C;&#x6211;&#x4EEC;push&#x8FDB;&#x7A0B;&#x7684;&#x4EFB;&#x52A1;&#x4E0D;&#x9700;&#x8981;&#x8FD9;&#x4E48;&#x65E9;&#x521D;&#x59CB;&#x5316;&#xFF0C;&#x56E0;&#x6B64;&#x62C9;&#x8D77;&#x5B50;&#x8FDB;&#x7A0B;&#x7684;&#x4EFB;&#x52A1;&#x5728;MainActivity&#x7684;onWindowFocusChanged&#x4E4B;&#x540E;&#x518D;&#x5F00;&#x59CB;&#x8C03;&#x5EA6;&#x3002;&#x8FD9;&#x4E00;&#x6761;&#x7684;&#x6536;&#x76CA;&#x5927;&#x6982;&#x662F;50&#xFF5E;100ms&#xFF0C;&#x6CE2;&#x52A8;&#x6BD4;&#x8F83;&#x5927;&#xFF0C;&#x4E0D;&#x80FD;&#x7CBE;&#x786E;&#x91CF;&#x5316;&#x3002;</p>
<h2 id="inflate">Inflate&#x4F18;&#x5316;</h2>
<p>&#x63A5;&#x4E0B;&#x6765;&#x6211;&#x4EEC;&#x89E3;&#x51B3;&#x4E3B;&#x7EBF;&#x7A0B;inflate&#x8017;&#x65F6;&#x957F;&#x7684;&#x95EE;&#x9898;&#xFF0C;&#x5E03;&#x5C40;Inflate&#x672C;&#x8EAB;&#x5C31;&#x662F;&#x4E00;&#x4E2A;&#x5F88;&#x8017;&#x65F6;&#x7684;&#x8FC7;&#x7A0B;&#xFF0C;&#x4E2D;&#x95F4;&#x6D89;&#x53CA;&#x5230;&#x8BFB;&#x53D6;XML&#x6587;&#x4EF6;&#xFF0C;&#x53CD;&#x5C04;&#x521B;&#x5EFA;View&#x7B49;&#x3002;&#x6240;&#x4EE5;Inflate&#x4F18;&#x5316;&#x4E00;&#x822C;&#x6709;&#x4E24;&#x4E2A;&#x601D;&#x8DEF;&#xFF0C;&#x4E00;&#x79CD;&#x662F;&#x628A;XML&#x5E03;&#x5C40;&#x8F6C;&#x4E3A;&#x5BF9;&#x7B49;&#x7684;Java&#x4EE3;&#x7801;&#xFF0C;&#x53E6;&#x4E00;&#x79CD;&#x5C31;&#x662F;&#x5F02;&#x6B65;Inflate&#x3002;&#x8F6C;Java&#x7684;&#x65B9;&#x6CD5;&#x6BD4;&#x8F83;&#x590D;&#x6742;&#xFF0C;&#x8981;&#x8003;&#x8651;&#x517C;&#x5BB9;&#x7CFB;&#x7EDF;&#x5DF2;&#x6709;&#x7684;&#x4E00;&#x4E9B;&#x903B;&#x8F91;&#xFF0C;&#x6BD4;&#x5982;AppCompat&#x7684;&#x517C;&#x5BB9;&#x8F6C;&#x6362;&#x7B49;&#xFF0C;&#x7ECF;&#x9A8C;&#x6570;&#x636E;&#x662F;&#x80FD;&#x8282;&#x7EA6;2/3&#x7684;inflate&#x65F6;&#x95F4;&#x3002;&#x8FD9;&#x91CC;&#x8981;&#x91CD;&#x70B9;&#x4ECB;&#x7ECD;&#x7684;&#x662F;&#x5F02;&#x6B65;Inflate&#x7684;&#x601D;&#x8DEF;&#x3002;<br>
&#x867D;&#x7136;Android&#x7684;UI&#x7EC4;&#x4EF6;&#x5E76;&#x4E0D;&#x662F;&#x7EBF;&#x7A0B;&#x5B89;&#x5168;&#x7684;&#xFF0C;&#x4F46;&#x662F;Inflate&#x5728;&#x6EE1;&#x8DB3;&#x7279;&#x5B9A;&#x6761;&#x4EF6;&#x7684;&#x60C5;&#x51B5;&#x4E0B;&#xFF0C;&#x662F;&#x53EF;&#x4EE5;&#x653E;&#x5728;&#x5F02;&#x6B65;&#x7EBF;&#x7A0B;&#x505A;&#x7684;&#x3002;Android SDK&#x4E5F;&#x63D0;&#x4F9B;&#x4E86;&#x4E00;&#x4E2A;&#x5DE5;&#x5177;&#x7C7B;AsyncLayoutInflater&#x3002;&#x4E00;&#x4E2A;Layout&#x5982;&#x679C;&#x6EE1;&#x8DB3;&#x5982;&#x4E0B;&#x6761;&#x4EF6;&#x5C31;&#x53EF;&#x4EE5;&#x88AB;&#x5F02;&#x6B65;Inflate&#xFF1A;</p>
<ol>
<li>&#x7236;&#x5E03;&#x5C40;&#x7684;generateLayoutParams&#x65B9;&#x6CD5;&#x662F;&#x7EBF;&#x7A0B;&#x5B89;&#x5168;&#x7684;</li>
<li>&#x5305;&#x542B;&#x7684;View&#x4E0D;&#x80FD;&#x5728;&#x6784;&#x9020;&#x5668;&#x4E2D;&#x521B;&#x5EFA;Handler&#x6216;&#x8005;&#x83B7;&#x53D6;Looper&#xFF0C;&#x56E0;&#x4E3A;&#x975E;&#x4E3B;&#x7EBF;&#x7A0B;&#x6CA1;&#x6709;&#x521B;&#x5EFA;Looper</li>
<li>XML&#x4E2D;&#x4E0D;&#x5305;&#x542B;Fragment</li>
</ol>
<p>&#x76F4;&#x63A5;&#x7528;&#x5B98;&#x65B9;&#x7684;AsyncLayoutInflater&#xFF0C;&#x6548;&#x679C;&#x4E0D;&#x4F1A;&#x5F88;&#x597D;&#xFF0C;AsyncLayoutInflater&#x4E0D;&#x5141;&#x8BB8;&#x8BBE;&#x7F6E;Factory&#x548C;Factory2&#xFF0C;&#x6211;&#x4EEC;&#x65E0;&#x6CD5;&#x505A;&#x5230;&#x5BF9;Context&#x7684;&#x66FF;&#x6362;&#xFF0C;&#x8FD9;&#x5C31;&#x610F;&#x5473;&#x7740;&#xFF0C;&#x6211;&#x4EEC;&#x6700;&#x65E9;&#x4E5F;&#x53EA;&#x80FD;&#x5728;Activity&#x7684;onCreate()&#x65B9;&#x6CD5;&#x4E2D;&#x5F00;&#x59CB;&#x5F02;&#x6B65;Inflate&#xFF0C;&#x8FD9;&#x4E2A;&#x65F6;&#x95F4;&#x592A;&#x665A;&#x4E86;&#xFF0C;&#x5F88;&#x591A;&#x65F6;&#x5019;&#x5F02;&#x6B65;&#x7EBF;&#x7A0B;&#x8FD8;&#x6CA1;&#x6765;&#x5F97;&#x53CA;Inflate&#x5B8C;&#xFF0C;&#x4E3B;&#x7EBF;&#x7A0B;&#x5DF2;&#x7ECF;&#x8981;&#x53D6;&#x4E86;&#xFF0C;&#x8FD9;&#x5C31;&#x4F1A;&#x9020;&#x6210;&#x4E3B;&#x7EBF;&#x7A0B;&#x7B49;&#x5F85;&#xFF0C;&#x6216;&#x8005;&#x662F;&#x4E3B;&#x7EBF;&#x7A0B;&#x4E8C;&#x6B21;Inflate&#x3002;&#x800C;&#x4E14;Activity#onCreate&#x7684;&#x65F6;&#x5019;&#xFF0C;CPU&#x8D1F;&#x8F7D;&#x672C;&#x6765;&#x5C31;&#x6BD4;&#x8F83;&#x91CD;&#xFF0C;&#x589E;&#x52A0;&#x5E76;&#x53D1;&#x4EFB;&#x52A1;&#x4E0D;&#x4E00;&#x5B9A;&#x6709;&#x6548;&#x679C;&#xFF0C;&#x5C24;&#x5176;&#x5728;&#x4F4E;&#x7AEF;&#x673A;&#x4E0A;&#x3002;&#x53EF;&#x4EE5;&#x770B;&#x4E0B;&#x9762;&#x8FD9;&#x5F20;&#x56FE;&#xFF0C;&#x5F88;&#x660E;&#x663E;&#x53EF;&#x4EE5;&#x770B;&#x5230;&#x4E00;&#x5927;&#x6BB5;&#x9501;&#x7B49;&#x5F85;&#xFF1A;<br>
<img src="https://github.com/shunix/BlogImages/blob/master/20200930_init_trace_8.png?raw=true" alt="init_trace_8" loading="lazy"><br>
&#x6700;&#x7406;&#x60F3;&#x7684;&#x60C5;&#x51B5;&#x662F;&#x5728;Application&#x521B;&#x5EFA;&#x8FC7;&#x7A0B;&#x4E2D;&#x5C31;&#x5B8C;&#x6210;&#x5F02;&#x6B65;Inflate&#xFF0C;&#x8FDB;&#x5230;Activity&#x65F6;&#xFF0C;&#x80AF;&#x5B9A;&#x6709;&#x5DF2;&#x7ECF;&#x53EF;&#x7528;&#x7684;&#x7ED3;&#x679C;&#x3002;&#x8FD9;&#x5C31;&#x5E26;&#x6765;&#x4E00;&#x4E2A;&#x95EE;&#x9898;&#xFF0C;Application&#x91CC;&#x9762;&#x7684;Context&#x548C;Activity&#x662F;&#x4E0D;&#x4E00;&#x6837;&#x7684;&#xFF0C;&#x7528;Application&#x7684;Context inflate&#x51FA;&#x6765;&#x7684;&#x5E03;&#x5C40;&#x585E;&#x4F1A;Activity&#x91CC;&#x4F1A;&#x51FA;&#x95EE;&#x9898;&#xFF0C;&#x8FD9;&#x5C31;&#x8981;&#x6C42;&#x6211;&#x4EEC;&#x80FD;&#x505A;&#x5230;Context&#x7684;&#x66FF;&#x6362;&#xFF0C;&#x7ED3;&#x5408;Factory2&#x548C;MutableContextWrapper&#xFF0C;&#x6211;&#x4EEC;&#x53EF;&#x4EE5;&#x5B8C;&#x6210;&#x4E0A;&#x8FF0;&#x6D41;&#x7A0B;&#x3002;<br>
&#x5148;&#x662F;Factory2&#x7684;&#x4EE3;&#x7801;&#xFF1A;</p>
<pre><code>class LInflateFactory : LayoutInflater.Factory2 {

    private val sClassPrefixList = arrayOf(
        &quot;android.widget.&quot;,
        &quot;android.view.&quot;,
        &quot;android.webkit.&quot;
    )

    private val sConstructorSignature = arrayOf(Context::class.java, AttributeSet::class.java)

    private val sConstructorMap: ArrayMap&lt;String, Constructor&lt;out View?&gt;&gt; = ArrayMap()

    override fun onCreateView(
        parent: View?,
        name: String,
        context: Context,
        attrs: AttributeSet
    ): View? {
        var realName = name
        if (name == &quot;view&quot;) {
            realName = attrs.getAttributeValue(null, &quot;class&quot;)
        }
        return if (-1 == name.indexOf(&apos;.&apos;)) {
            for (i in sClassPrefixList.indices) {
                val view =
                    createViewByPrefix(context, attrs, realName, sClassPrefixList[i])
                if (view != null) {
                    return view
                }
            }
            null
        } else {
            createViewByPrefix(context, attrs, name, null)
        }
    }


    private fun createViewByPrefix(
        context: Context,
        attrs: AttributeSet,
        name: String,
        prefix: String?
    ): View? {
        var constructor = sConstructorMap[name]
        return try {
            if (constructor == null) {
                val clazz = Class.forName(
                    if (prefix != null) prefix + name else name,
                    false,
                    context.classLoader
                ).asSubclass(View::class.java)
                constructor = clazz.getConstructor(*sConstructorSignature)
                sConstructorMap[name] = constructor
            }
            constructor.isAccessible = true
            constructor.newInstance(MutableContextWrapper(context).apply {
                val originalTheme = context.packageManager.getApplicationInfo(packageName, 0).theme
                setTheme(originalTheme)
            }, attrs)
        } catch (e: Exception) {
            null
        }
    }



    override fun onCreateView(name: String, context: Context, attrs: AttributeSet): View? {
        return null
    }
}
</code></pre>
<p>&#x5728;&#x521B;&#x5EFA;View&#x7684;&#x65F6;&#x5019;&#xFF0C;&#x6211;&#x4EEC;&#x628A;Context&#x7528;MutableContextWrapper&#x5305;&#x4E86;&#x4E00;&#x5C42;&#xFF0C;&#x8FD9;&#x91CC;&#x8981;&#x6CE8;&#x610F;&#xFF0C;theme&#x8981;&#x5904;&#x7406;&#x597D;&#xFF0C;&#x6709;&#x4E00;&#x4E9B;View&#xFF0C;&#x6BD4;&#x5982;AppBarLayout&#x4F1A;&#x68C0;&#x6D4B;theme&#x662F;&#x5426;&#x6B63;&#x786E;&#xFF0C;&#x6240;&#x4EE5;&#x8981;&#x4ECE;&#x539F;&#x6765;&#x7684;context&#x91CC;&#x628A;theme&#x53D6;&#x51FA;&#x6765;&#xFF0C;&#x7ED9;MutableContextWrapper&#x8BBE;&#x7F6E;&#x4E0A;&#x3002;<br>
&#x7136;&#x540E;&#x662F;&#x81EA;&#x5B9A;&#x4E49;&#x7684;LayoutInflater&#xFF1A;</p>
<pre><code>class LLayoutInflater(context: Context) : LayoutInflater(context) {
    companion object {
        fun inflate(context: Context, @LayoutRes layoutId: Int): View {
            return LLayoutInflater(context).run {
                LayoutInflaterCompat.setFactory2(this, LInflateFactory())
                inflate(layoutId, null, false)
            }
        }
    }

    override fun cloneInContext(newContext: Context?): LayoutInflater {
        return LLayoutInflater(context)
    }
}
</code></pre>
<p>&#x6700;&#x540E;&#x63D0;&#x4F9B;&#x4E00;&#x4E2A;&#x5DE5;&#x5177;&#x7C7B;&#xFF0C;&#x5728;&#x53D6;&#x7684;&#x65F6;&#x5019;&#x4F20;&#x5165;Acitivity&#xFF0C;&#x81EA;&#x52A8;&#x5B8C;&#x6210;context&#x7684;&#x66FF;&#x6362;&#xFF1A;</p>
<pre><code>object LAsyncInflateHolder {
    private val mPool = SparseArray&lt;View&gt;()
    private val mLock = ReentrantLock()

    private const val TAG = &quot;LAsyncInflate&quot;

    fun asyncInflate(@LayoutRes layoutId: Int) {
        ThreadManager.inflateExecutor.submit {
            mLock.withLock {
                mPool.append(layoutId, LLayoutInflater.inflate(BaseApplication.instance, layoutId))
            }
        }
    }

    @UiThread
    fun tryGetView(activity: Activity, @LayoutRes layoutId: Int): View? {
        mLock.withLock {
            return if (mPool.indexOfKey(layoutId) &lt; 0) {
                Log.d(TAG, &quot;$layoutId null&quot;)
                null
            } else {
                val view = mPool[layoutId].apply {
                    (context as? MutableContextWrapper)?.baseContext = activity
                }
                mPool.remove(layoutId)
                view
            }
        }
    }
}
</code></pre>
<p>&#x4ECE;trace&#x91CC;&#x53EF;&#x4EE5;&#x770B;&#x5230;&#x6548;&#x679C;&#xFF1A;<br>
<img src="https://github.com/shunix/BlogImages/blob/master/20200930_init_trace_9.png?raw=true" alt="init_trace_9" loading="lazy"></p>
<h2 id>&#x975E;&#x5FC5;&#x987B;&#x4EFB;&#x52A1;&#x5EF6;&#x540E;</h2>
<p>&#x6700;&#x540E;&#x4E00;&#x9879;&#x662F;&#x504F;&#x4E1A;&#x52A1;&#x7684;&#x4F18;&#x5316;&#xFF0C;&#x5E94;&#x8BE5;&#x4ECE;&#x4E1A;&#x52A1;&#x89D2;&#x5EA6;&#x62C6;&#x51FA;&#x6765;&#x542F;&#x52A8;&#x4EFB;&#x52A1;&#x7684;&#x4F18;&#x5148;&#x7EA7;&#xFF0C;&#x8FD9;&#x6B21;&#x542F;&#x52A8;&#x4F18;&#x5316;&#xFF0C;&#x4E00;&#x5171;&#x68B3;&#x7406;&#x4E86;40+&#x542F;&#x52A8;&#x4EFB;&#x52A1;&#xFF0C;&#x6709;&#x597D;&#x51E0;&#x4E2A;&#x90FD;&#x662F;&#x6CA1;&#x5FC5;&#x8981;&#x5728;&#x542F;&#x52A8;&#x9636;&#x6BB5;&#x505A;&#x7684;&#xFF0C;&#x5B8C;&#x5168;&#x53EF;&#x4EE5;&#x653E;&#x5230;&#x4E1A;&#x52A1;&#x4F7F;&#x7528;&#x65F6;&#x505A;&#x61D2;&#x52A0;&#x8F7D;&#xFF0C;&#x5728;&#x589E;&#x52A0;&#x542F;&#x52A8;&#x4EFB;&#x52A1;&#x65F6;&#x5E94;&#x8BE5;&#x5148;&#x8003;&#x8651;&#x662F;&#x4E0D;&#x662F;&#x4E00;&#x5B9A;&#x8981;&#x653E;&#x5728;&#x542F;&#x52A8;&#x9636;&#x6BB5;&#x521D;&#x59CB;&#x5316;&#xFF0C;&#x80FD;&#x4E0D;&#x80FD;&#x505A;&#x61D2;&#x52A0;&#x8F7D;&#xFF1F;<br>
&#x4ECE;&#x4E1A;&#x52A1;&#x4E0A;&#x6765;&#x770B;&#xFF0C;&#x5C0F;&#x6982;&#x7387;&#x573A;&#x666F;&#x9700;&#x8981;&#x7684;&#x80FD;&#x529B;&#x5E94;&#x8BE5;&#x5728;&#x7528;&#x5230;&#x65F6;&#x505A;&#x61D2;&#x52A0;&#x8F7D;&#xFF0C;&#x4E3A;&#x4E86;&#x5C0F;&#x90E8;&#x5206;&#x7528;&#x6237;&#x727A;&#x7272;&#x5927;&#x90E8;&#x5206;&#x7528;&#x6237;&#x7684;&#x4F53;&#x9A8C;&#x662F;&#x4E0D;&#x5212;&#x7B97;&#x7684;&#xFF0C;&#x7814;&#x53D1;&#x5728;&#x505A;&#x4E1A;&#x52A1;&#x5F00;&#x53D1;&#x65F6;&#x4E5F;&#x8981;&#x6709;&#x8FD9;&#x79CD;&#x610F;&#x8BC6;&#x3002;</p>
<h2 id>&#x6548;&#x679C;</h2>
<p>&#x5728;Oppo 2G+8&#x6838;&#x8054;&#x53D1;&#x79D1;&#x7684;&#x624B;&#x673A;&#x4E0A;&#xFF0C;&#x542F;&#x52A8;&#x65F6;&#x95F4;&#x4ECE;&#x5E73;&#x5747;&#x503C;2.22s&#x964D;&#x4F4E;&#x5230;&#x4E86;1.58s&#x5DE6;&#x53F3;<br>
&#x5728;&#x5C0F;&#x7C73;MIX 2S&#xFF08;6G+&#x9A81;&#x9F99;845&#xFF09;&#x4E0A;&#xFF0C;&#x542F;&#x52A8;&#x65F6;&#x95F4;&#x5747;&#x503C;0.51s</p>
<h1 id>&#x4F18;&#x5316;&#x6574;&#x4F53;&#x601D;&#x8DEF;</h1>
<p>&#x4E0D;&#x6B62;&#x5C40;&#x9650;&#x4E8E;&#x542F;&#x52A8;&#x4F18;&#x5316;&#xFF0C;&#x6027;&#x80FD;&#x4F18;&#x5316;&#x7684;&#x6574;&#x4F53;&#x601D;&#x8DEF;&#x662F;&#x901A;&#x7528;&#x7684;&#xFF0C;&#x53EF;&#x4EE5;&#x5F52;&#x7EB3;&#x4E3A;&#x5982;&#x4E0B;&#x6D41;&#x7A0B;&#xFF1A;<br>
<img src="https://github.com/shunix/BlogImages/blob/master/20200930_opt_ring.png?raw=true" alt="opt_ring" loading="lazy"><br>
&#x7EBF;&#x4E0B;&#x89C2;&#x5BDF;&#x7684;&#x7ED3;&#x679C;&#xFF0C;&#x56E0;&#x4E3A;&#x4EBA;&#x4E3A;&#x8BEF;&#x5DEE;&#x6216;&#x8005;&#x673A;&#x578B;&#x4E0D;&#x8DB3;&#x7684;&#x539F;&#x56E0;&#xFF0C;&#x53EF;&#x80FD;&#x4E0D;&#x51C6;&#x786E;&#xFF0C;&#x4E00;&#x5B9A;&#x8981;&#x4EE5;&#x7EBF;&#x4E0A;&#x6570;&#x636E;&#x4E3A;&#x51C6;&#x3002;&#x6027;&#x80FD;&#x4F18;&#x5316;&#x4E00;&#x822C;&#x4F1A;&#x6D89;&#x53CA;&#x5230;&#x4E1A;&#x52A1;&#x7684;&#x91CD;&#x6784;&#x548C;&#x6539;&#x9020;&#xFF0C;&#x6539;&#x7684;&#x4EBA;&#x4E0D;&#x4E00;&#x5B9A;&#x4E86;&#x89E3;&#x4E1A;&#x52A1;&#xFF0C;QA&#x7684;&#x56DE;&#x5F52;&#x529B;&#x5EA6;&#x4E5F;&#x4E0D;&#x5982;&#x4E4B;&#x524D;&#x4E1A;&#x52A1;&#x5F00;&#x53D1;&#x7684;&#x65F6;&#x5019;&#xFF0C;&#x6240;&#x4EE5;&#x7070;&#x5EA6;&#x5F88;&#x6709;&#x5FC5;&#x8981;&#xFF0C;&#x89C2;&#x5BDF;&#x6709;&#x6CA1;&#x6709;&#x9700;&#x8981;&#x53D1;&#x7248;&#x7684;&#x95EE;&#x9898;&#x3002;</p>
<h2 id>&#x9632;&#x52A3;&#x5316;</h2>
<p>&#x8FD9;&#x91CC;&#x8981;&#x91CD;&#x70B9;&#x8BF4;&#x7684;&#x5C31;&#x662F;&#x9632;&#x52A3;&#x5316;&#xFF0C;&#x542F;&#x52A8;&#x4F18;&#x5316;&#x7684;&#x9632;&#x52A3;&#x5316;&#x8981;&#x4ECE;&#x4E24;&#x4E2A;&#x65B9;&#x9762;&#x5165;&#x624B;&#xFF0C;&#x51C6;&#x5165;&#x548C;&#x6301;&#x7EED;&#x76D1;&#x63A7;&#x3002;<br>
&#x6211;&#x4EEC;&#x9879;&#x76EE;&#x628A;&#x6240;&#x6709;&#x542F;&#x52A8;&#x7684;Task&#x6536;&#x5728;&#x4E00;&#x4E2A;&#x5305;&#x4E0B;&#xFF0C;&#x901A;&#x8FC7;SPI&#x7684;&#x65B9;&#x5F0F;&#x8C03;&#x7528;&#x5176;&#x4ED6;&#x4E1A;&#x52A1;&#x6A21;&#x5757;&#x5B8C;&#x6210;&#x521D;&#x59CB;&#x5316;&#xFF0C;&#x6240;&#x4EE5;&#x53EF;&#x4EE5;&#x5728;MR&#x7684;&#x65F6;&#x5019;&#x5BF9;&#x8FD9;&#x4E2A;&#x5305;&#x4EE5;&#x53CA;Application&#x548C;MainActivity&#x505A;&#x5F3A;&#x5236;CR&#xFF0C;&#x8981;&#x6C42;&#x542F;&#x52A8;&#x7684;owner&#x901A;&#x8FC7;&#x540E;&#x624D;&#x80FD;&#x5408;&#x5165;&#x3002;&#x8FD9;&#x79CD;&#x529B;&#x5EA6;&#x7684;&#x51C6;&#x5165;&#x53EA;&#x80FD;&#x505A;&#x5230;&#x542F;&#x52A8;&#x9636;&#x6BB5;&#x4E0D;&#x589E;&#x52A0;&#x65B0;&#x4EFB;&#x52A1;&#xFF0C;&#x5982;&#x679C;&#x662F;&#x5DF2;&#x6709;&#x7684;&#x542F;&#x52A8;&#x4EFB;&#x52A1;&#x903B;&#x8F91;&#x53D8;&#x66F4;&#x5BFC;&#x81F4;&#x7684;&#x6027;&#x80FD;&#x52A3;&#x5316;&#xFF0C;&#x901A;&#x8FC7;CR&#x5F88;&#x96BE;&#x53D1;&#x73B0;&#xFF0C;&#x8FD9;&#x5C31;&#x9700;&#x8981;QA&#x914D;&#x5408;&#x505A;&#x6301;&#x7EED;&#x7684;&#x81EA;&#x52A8;&#x5316;&#x6D4B;&#x8BD5;&#x3002;&#x5728;git&#x7684;pipeline&#x4E2D;&#x52A0;&#x5165;&#x81EA;&#x52A8;&#x5316;&#x4E5F;&#x662F;&#x5F88;&#x91CD;&#x8981;&#x7684;&#x9632;&#x52A3;&#x5316;&#x624B;&#x6BB5;&#x3002;</p>
<h1 id>&#x53EF;&#x80FD;&#x7684;&#x4F18;&#x5316;&#x70B9;</h1>
<p>&#x8FD9;&#x6B21;&#x505A;&#x542F;&#x52A8;&#x4F18;&#x5316;&#x7684;&#x65F6;&#x95F4;&#x6BD4;&#x8F83;&#x7D27;&#xFF0C;&#x53EA;&#x505A;&#x4E86;ROI&#x9AD8;&#x7684;&#x90E8;&#x5206;&#xFF0C;&#x6709;&#x4E00;&#x4E9B;&#x56E0;&#x4E3A;&#x4F18;&#x5148;&#x7EA7;&#x4E0D;&#x9AD8;&#x6216;&#x8005;&#x5BA2;&#x89C2;&#x539F;&#x56E0;&#x6CA1;&#x6709;&#x505A;&#x7684;&#xFF0C;&#x6211;&#x4E5F;&#x5217;&#x4E86;&#x4E0B;&#x6765;&#xFF0C;&#x65B9;&#x4FBF;&#x4EE5;&#x540E;&#x6392;&#x6280;&#x672F;&#x9700;&#x6C42;&#x6216;&#x5176;&#x4ED6;&#x9879;&#x76EE;&#x53C2;&#x8003;&#x3002;</p>
<h2 id>&#x542F;&#x52A8;&#x63A5;&#x53E3;&#x6536;&#x655B;</h2>
<p>&#x542F;&#x52A8;&#x9636;&#x6BB5;&#x7F51;&#x7EDC;&#x8BF7;&#x6C42;&#x5E94;&#x8BE5;&#x6536;&#x655B;&#xFF0C;&#x53EF;&#x4EE5;&#x901A;&#x8FC7;&#x5EF6;&#x540E;&#x8BF7;&#x6C42;&#x6216;&#x8005;&#x63A5;&#x53E3;&#x5408;&#x5E76;&#x7684;&#x65B9;&#x5F0F;&#x6765;&#x505A;&#xFF0C;&#x9700;&#x8981;&#x670D;&#x52A1;&#x7AEF;&#x914D;&#x5408;&#x4E00;&#x8D77;&#x505A;&#xFF0C;&#x56E0;&#x4E3A;&#x4EBA;&#x529B;&#x95EE;&#x9898;&#xFF0C;&#x6682;&#x672A;&#x5B9E;&#x73B0;&#x3002;</p>
<h2 id="sharedpreferences">&#x63D0;&#x524D;&#x52A0;&#x8F7D;SharedPreferences</h2>
<p>SP&#x5728;&#x7B2C;&#x4E00;&#x6B21;&#x8BFB;&#x53D6;&#x65F6;&#xFF0C;&#x4F1A;&#x4E00;&#x6B21;&#x6027;&#x4ECE;&#x78C1;&#x76D8;&#x8BFB;&#x5165;&#x5185;&#x5B58;&#xFF0C;&#x53EF;&#x4EE5;&#x505A;&#x9884;&#x52A0;&#x8F7D;&#x3002;&#x56E0;&#x4E3A;&#x9879;&#x76EE;&#x4E1A;&#x52A1;&#x4EE3;&#x7801;&#x5DF2;&#x7ECF;&#x5168;&#x90E8;&#x4F7F;&#x7528;&#x4E86;&#x81EA;&#x7814;&#x57FA;&#x4E8E;mmap&#x7684;&#x5B9E;&#x73B0;&#xFF0C;&#x672A;&#x4F7F;&#x7528;SP&#xFF0C;&#x53EA;&#x6709;&#x90E8;&#x5206;&#x4E8C;&#x65B9;&#x4E09;&#x65B9;&#x5E93;&#x5728;&#x4F7F;&#x7528;SP&#xFF0C;ROI&#x8F83;&#x4F4E;&#x3002;</p>
<h2 id>&#x63D0;&#x524D;&#x52A0;&#x8F7D;&#x542F;&#x52A8;&#x9636;&#x6BB5;&#x9700;&#x8981;&#x7684;&#x7C7B;</h2>
<p>&#x5F00;&#x5F02;&#x6B65;&#x4EFB;&#x52A1;&#xFF0C;&#x63D0;&#x524D;&#x7528;Class.forName()&#x52A0;&#x8F7D;&#x6240;&#x6709;&#x542F;&#x52A8;&#x9636;&#x6BB5;&#x7528;&#x5230;&#x7684;&#x7C7B;&#x3002;&#x4E4B;&#x524D;&#x9879;&#x76EE;&#x6709;&#x7528;&#x8FC7;&#xFF0C;&#x6548;&#x679C;&#x4E00;&#x822C;&#xFF0C;&#x80FD;&#x7701;&#x4E2A;15&#xFF5E;30ms&#x5DE6;&#x53F3;&#xFF0C;&#x4EE3;&#x4EF7;&#x662F;&#x975E;&#x5E38;&#x96BE;&#x7EF4;&#x62A4;&#xFF0C;&#x9700;&#x8981;&#x7528;&#x6CE8;&#x89E3;&#x6765;&#x6807;&#x8BB0;&#x6BCF;&#x4E00;&#x4E2A;&#x542F;&#x52A8;&#x9636;&#x6BB5;&#x8981;&#x7528;&#x5230;&#x7684;&#x7C7B;&#xFF0C;&#x6216;&#x8005;&#x81EA;&#x5DF1;&#x7EF4;&#x62A4;&#x5217;&#x8868;&#x3002;</p>
<h2 id="redex">Redex</h2>
<p>&#x63A5;&#x5165;Facebook&#x7684;redex&#x3002;&#x65F6;&#x95F4;&#x6BD4;&#x8F83;&#x7D27;&#x5F20;&#xFF0C;&#x6CA1;&#x80FD;&#x5BF9;redex&#x505A;&#x6280;&#x672F;&#x9884;&#x7814;&#xFF0C;&#x65E0;&#x6CD5;&#x8BC4;&#x4F30;&#x6536;&#x76CA;&#xFF0C;&#x62C5;&#x5FC3;&#x5F71;&#x54CD;&#x7EBF;&#x4E0A;&#x7A33;&#x5B9A;&#x6027;&#xFF0C;&#x6682;&#x672A;&#x4F7F;&#x7528;&#x3002;</p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[关于SSL Pinning的一切]]></title><description><![CDATA[<!--kg-card-begin: markdown--><h1 id>&#x80CC;&#x666F;</h1>
<p>HTTPS&#x5F53;&#x4E0B;&#x5DF2;&#x7ECF;&#x975E;&#x5E38;&#x666E;&#x904D;&#xFF0C;HTTPS&#x5168;&#x79F0;&#x662F;Hypertext Transfer Protocol Secure&#xFF0C;&#x5728;HTTP&#x57FA;&#x7840;&#x4E0A;&#x589E;&#x52A0;&#x4E86;TLS&#x52A0;&#x5BC6;&#xFF0C;&#x867D;&#x7136;&#x540D;&#x5B57;&#x91CC;&#x6709;&#x4E2A;Secure&#xFF0C;&#x4F46;HTTPS&#x5E76;&#x4E0D;&#x662F;&#x7EDD;&#x5BF9;&#x5B89;</p>]]></description><link>https://shunix.com/ssl-pinning/</link><guid isPermaLink="false">60812ae62b3f873b19511ecb</guid><category><![CDATA[技术文章]]></category><dc:creator><![CDATA[Shunix]]></dc:creator><pubDate>Thu, 24 Sep 2020 10:24:50 GMT</pubDate><content:encoded><![CDATA[<!--kg-card-begin: markdown--><h1 id>&#x80CC;&#x666F;</h1>
<p>HTTPS&#x5F53;&#x4E0B;&#x5DF2;&#x7ECF;&#x975E;&#x5E38;&#x666E;&#x904D;&#xFF0C;HTTPS&#x5168;&#x79F0;&#x662F;Hypertext Transfer Protocol Secure&#xFF0C;&#x5728;HTTP&#x57FA;&#x7840;&#x4E0A;&#x589E;&#x52A0;&#x4E86;TLS&#x52A0;&#x5BC6;&#xFF0C;&#x867D;&#x7136;&#x540D;&#x5B57;&#x91CC;&#x6709;&#x4E2A;Secure&#xFF0C;&#x4F46;HTTPS&#x5E76;&#x4E0D;&#x662F;&#x7EDD;&#x5BF9;&#x5B89;&#x5168;&#x7684;&#xFF0C;&#x4F9D;&#x7136;&#x5B58;&#x5728;&#x88AB;&#x4E2D;&#x95F4;&#x4EBA;&#x653B;&#x51FB;&#xFF08;<br>
Man-in-the-middle attack&#xFF09;&#x7684;&#x98CE;&#x9669;&#xFF0C;&#x8FDB;&#x800C;&#x5BFC;&#x81F4;&#x5E94;&#x7528;&#x88AB;&#x6293;&#x5305;&#xFF0C;HTTPS&#x7684;&#x52A0;&#x5BC6;&#x6D41;&#x91CF;&#x88AB;&#x83B7;&#x53D6;&#x3002;</p>
<h2 id="mitm">MITM&#x4E2D;&#x95F4;&#x4EBA;&#x653B;&#x51FB;</h2>
<h3 id>&#x6982;&#x5FF5;</h3>
<p>&#x8FD9;&#x91CC;&#x4E3E;&#x4E2A;&#x7B80;&#x5355;&#x7684;&#x4F8B;&#x5B50;&#xFF0C;&#x5E2E;&#x52A9;&#x4E0D;&#x4E86;&#x89E3;MITM&#x7684;&#x8BFB;&#x8005;&#x7406;&#x89E3;&#xFF1A;&#x5047;&#x5982;A&#x548C;B&#x9700;&#x8981;&#x901A;&#x4FE1;&#xFF0C;&#x8FD9;&#x4E2A;&#x65F6;&#x5019;&#x6765;&#x4E86;&#x4E00;&#x4E2A;C&#xFF0C;C&#x544A;&#x8BC9;A&#x81EA;&#x5DF1;&#x662F;B&#xFF0C;&#x540C;&#x65F6;&#x544A;&#x8BC9;B&#x81EA;&#x5DF1;&#x662F;A&#xFF0C;A&#x548C;B&#x90FD;&#x4EE5;&#x4E3A;&#x81EA;&#x5DF1;&#x5728;&#x548C;&#x5BF9;&#x65B9;&#x901A;&#x4FE1;&#xFF0C;&#x5B9E;&#x9645;&#x4E0A;&#x770B;&#x5230;&#x7684;&#x6D88;&#x606F;&#x90FD;&#x662F;&#x7531;C&#x8F6C;&#x53D1;&#x7684;&#xFF0C;C&#x5C31;&#x53EF;&#x4EE5;&#x5728;&#x8FD9;&#x4E2A;&#x8FC7;&#x7A0B;&#x4E2D;&#x5B8C;&#x6210;&#x76D1;&#x542C;&#x548C;&#x7BE1;&#x6539;&#xFF0C;&#x8FD9;&#x5C31;&#x662F;&#x4E2D;&#x95F4;&#x4EBA;&#x653B;&#x51FB;&#x3002;</p>
<h3 id="arp">ARP&#x6B3A;&#x9A97;</h3>
<p>&#x5728;&#x771F;&#x5B9E;&#x7684;&#x7F51;&#x7EDC;&#x4E2D;&#xFF0C;&#x8981;&#x5B8C;&#x6210;&#x4E0A;&#x8FF0;&#x7684;&#x8FC7;&#x7A0B;&#xFF0C;&#x9700;&#x8981;&#x501F;&#x52A9;ARP&#x6B3A;&#x9A97;&#x3002;ARP&#x662F;&#x5C40;&#x57DF;&#x7F51;&#x4E2D;&#x7528;IP&#x6765;&#x67E5;&#x627E;MAC&#x5730;&#x5740;&#x7684;&#x534F;&#x8BAE;&#xFF0C;&#x6B63;&#x5E38;&#x7684;ARP&#x67E5;&#x627E;&#x8FC7;&#x7A0B;&#x4E2D;&#xFF0C;&#x8BF7;&#x6C42;&#x7684;&#x4E3B;&#x673A;&#x4F1A;&#x5411;&#x5C40;&#x57DF;&#x7F51;&#x53D1;&#x9001;&#x5E7F;&#x64AD;&#xFF0C;&#x67E5;&#x8BE2;&#x5BF9;&#x5E94;IP&#x7684;MAC&#x5730;&#x5740;&#xFF0C;&#x5C40;&#x57DF;&#x7F51;&#x7684;&#x5176;&#x4ED6;&#x4E3B;&#x673A;&#x5982;&#x679C;&#x4E0D;&#x662F;&#x8FD9;&#x4E2A;IP&#x5C31;&#x4F1A;&#x5FFD;&#x7565;&#x8BF7;&#x6C42;&#xFF0C;&#x5BF9;&#x5E94;IP&#x7684;&#x4E3B;&#x673A;&#x4F1A;&#x56DE;&#x5E94;&#x81EA;&#x5DF1;&#x7684;MAC&#x5730;&#x5740;&#x3002;&#x4F46;&#x662F;ARP&#x534F;&#x8BAE;&#x5728;&#x673A;&#x5236;&#x4E0A;&#x5C31;&#x6CA1;&#x6709;&#x8003;&#x8651;&#x6821;&#x9A8C;&#x7684;&#x60C5;&#x51B5;&#xFF0C;&#x53EA;&#x8981;&#x6536;&#x5230;&#x4E00;&#x4E2A;ARP&#x56DE;&#x5E94;&#xFF0C;&#x4E3B;&#x673A;&#x5C31;&#x4F1A;&#x66F4;&#x65B0;&#x81EA;&#x5DF1;&#x7684;ARP&#x8868;&#x3002;ARP&#x534F;&#x8BAE;&#x7684;&#x7B80;&#x5355;&#x7C97;&#x66B4;&#xFF0C;&#x8BA9;ARP&#x6B3A;&#x9A97;&#x53D8;&#x5F97;&#x975E;&#x5E38;&#x7B80;&#x5355;&#x3002;&#x653B;&#x51FB;&#x8005;&#x53EA;&#x9700;&#x8981;&#x5F80;&#x4E00;&#x4E2A;&#x5C40;&#x57DF;&#x7F51;&#x4E0D;&#x65AD;&#x53D1;&#x9001;ARP&#x56DE;&#x5E94;&#xFF0C;&#x5C31;&#x80FD;&#x66F4;&#x65B0;&#x5404;&#x4E2A;&#x4E3B;&#x673A;&#x7684;ARP&#x8868;&#xFF0C;&#x4ECE;&#x800C;&#x8FBE;&#x5230;&#x4E0A;&#x9762;&#x4E00;&#x8282;&#x8BF4;&#x7684;&#x76EE;&#x7684;&#xFF0C;&#x8FD9;&#x4E2A;&#x8FC7;&#x7A0B;&#x4E5F;&#x88AB;&#x53EB;&#x505A;ARP&#x6295;&#x6BD2;&#x3002;&#x5F53;&#x7136;&#xFF0C;&#x66F4;&#x5927;&#x8303;&#x56F4;&#x7684;&#x4E2D;&#x95F4;&#x4EBA;&#x653B;&#x51FB;&#x9700;&#x8981;&#x501F;&#x52A9;DNS&#x6295;&#x6BD2;&#xFF0C;&#x8FD9;&#x4E2A;&#x5C31;&#x4E0D;&#x7EC6;&#x8BF4;&#xFF0C;&#x539F;&#x7406;&#x5927;&#x81F4;&#x7C7B;&#x4F3C;&#x3002;</p>
<h3 id="httpsmitm">&#x9488;&#x5BF9;HTTPS&#x7684;MITM</h3>
<p>HTTPS&#x5728;&#x8BBE;&#x8BA1;&#x4E0A;&#x662F;&#x8003;&#x8651;&#x5230;&#x4E86;&#x4E2D;&#x95F4;&#x4EBA;&#x653B;&#x51FB;&#x7684;&#x60C5;&#x51B5;&#x7684;&#xFF0C;TLS&#x662F;&#x652F;&#x6301;&#x53CC;&#x5411;&#x8BA4;&#x8BC1;&#x7684;&#xFF08;&#x4E00;&#x822C;&#x53EA;&#x9700;&#x8981;&#x5BA2;&#x6237;&#x7AEF;&#x6821;&#x9A8C;&#x670D;&#x52A1;&#x7AEF;&#x8EAB;&#x4EFD;&#xFF09;&#xFF0C;&#x90A3;&#x4E48;&#x4E3A;&#x4EC0;&#x4E48;&#x8FD8;&#x4F1A;&#x5B58;&#x5728;&#x4E2D;&#x95F4;&#x4EBA;&#x653B;&#x51FB;&#x7684;&#x98CE;&#x9669;&#x5462;&#xFF1F;TLS&#x7684;&#x8BA4;&#x8BC1;&#x673A;&#x5236;&#x662F;&#x57FA;&#x4E8E;&#x8BC1;&#x4E66;&#x7684;&#xFF0C;&#x5173;&#x4E8E;&#x8BC1;&#x4E66;&#x7684;&#x7EC6;&#x8282;&#x6211;&#x4EEC;&#x4F1A;&#x5728;&#x540E;&#x9762;&#x7684;&#x7BC7;&#x5E45;&#x91CC;&#x7EC6;&#x8BB2;&#xFF0C;&#x8FD9;&#x91CC;&#x4E0D;&#x5C55;&#x5F00;&#x3002;&#x6211;&#x4EEC;&#x5982;&#x679C;&#x6CA1;&#x6709;&#x4FE1;&#x4EFB;&#x4E00;&#x4E9B;&#x5947;&#x5947;&#x602A;&#x602A;&#x7684;&#x8BC1;&#x4E66;&#xFF0C;TLS&#x662F;&#x53EF;&#x4EE5;&#x4FDD;&#x8BC1;&#x901A;&#x4FE1;&#x5B89;&#x5168;&#x7684;&#xFF0C;&#x5426;&#x5219;&#x5C31;&#x4F1A;&#x5BFC;&#x81F4;TLS&#x7684;&#x8BA4;&#x8BC1;&#x673A;&#x5236;&#x5931;&#x6548;&#xFF0C;&#x4ECE;&#x800C;&#x88AB;&#x4E2D;&#x95F4;&#x4EBA;&#x653B;&#x51FB;&#x3002;</p>
<h2 id>&#x6293;&#x5305;</h2>
<p>&#x6293;&#x5305;&#x5C31;&#x662F;&#x4E00;&#x4E2A;MITM&#x7684;&#x5E94;&#x7528;&#x573A;&#x666F;&#xFF0C;&#x8FD9;&#x91CC;&#x4EE5;&#x5E38;&#x7528;&#x7684;Charles&#x4E3A;&#x4F8B;&#xFF0C;&#x770B;&#x770B;HTTPS&#x7684;&#x52A0;&#x5BC6;&#x662F;&#x5982;&#x4F55;&#x88AB;&#x7ED5;&#x8FC7;&#x7684;&#x3002;&#x6211;&#x4EEC;&#x77E5;&#x9053;&#xFF0C;&#x5982;&#x679C;&#x8981;&#x89E3;&#x5BC6;HTTPS&#x6D41;&#x91CF;&#xFF0C;Charles&#x4F1A;&#x5F15;&#x5BFC;&#x6211;&#x4EEC;&#x7ED9;&#x624B;&#x673A;&#x5B89;&#x88C5;&#x4E00;&#x4E2A;&#x6839;&#x8BC1;&#x4E66;&#xFF0C;&#x7528;&#x6587;&#x672C;&#x7F16;&#x8F91;&#x5668;&#x6253;&#x5F00;&#x53EF;&#x4EE5;&#x770B;&#x51FA;&#x662F;&#x6807;&#x51C6;&#x7684;pem&#x683C;&#x5F0F;&#xFF1A;</p>
<pre><code>-----BEGIN CERTIFICATE-----
MIIFQDCCBCigAwIBAgIGAXSrxEHXMA0GCSqGSIb3DQEBCwUAMIGkMTUwMwYDVQQD
DCxDaGFybGVzIFByb3h5IENBICgyMCBTZXAgMjAyMCwgQzAyRDM3RUhNRDZSKTEl
MCMGA1UECwwcaHR0cHM6Ly9jaGFybGVzcHJveHkuY29tL3NzbDERMA8GA1UECgwI
WEs3MiBMdGQxETAPBgNVBAcMCEF1Y2tsYW5kMREwDwYDVQQIDAhBdWNrbGFuZDEL
MAkGA1UEBhMCTlowHhcNMDAwMTAxMDAwMDAwWhcNNDkxMTE3MTM0NjM5WjCBpDE1
MDMGA1UEAwwsQ2hhcmxlcyBQcm94eSBDQSAoMjAgU2VwIDIwMjAsIEMwMkQzN0VI
TUQ2UikxJTAjBgNVBAsMHGh0dHBzOi8vY2hhcmxlc3Byb3h5LmNvbS9zc2wxETAP
BgNVBAoMCFhLNzIgTHRkMREwDwYDVQQHDAhBdWNrbGFuZDERMA8GA1UECAwIQXVj
a2xhbmQxCzAJBgNVBAYTAk5aMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC
AQEAoMCTz31wG8zGwexoelqWd+q9WzQHtkFCReKjw0qRZ/8gjmUuj6pdmEg6FQFr
f9gnIiyPeME+J1gOfIp3z9i860VjviQGUwuPCBuU8G0eXBYZOE2kJvKx1G5QeI/c
hnGi3a3Sk5bGBUV1mMbS35OUkFVgvBygVyEjOF1SKDM/IT9jh5QV8uzhObDk+0F6
mjZ+uug2CDdQLNd4VqMClXrDaFk2gVpcnDatNI0p6doBlsxMedIFw0wPJaXfdl1M
CkPOwqgDpgh4J/3roGwJ5ky9zbE7l552jm/UjTRt5X7608IO5G0Kd5OutvxyqmZU
mYLDS0wcS+vZrPA6WwPUgT+TeQIDAQABo4IBdDCCAXAwDwYDVR0TAQH/BAUwAwEB
/zCCASwGCWCGSAGG+EIBDQSCAR0TggEZVGhpcyBSb290IGNlcnRpZmljYXRlIHdh
cyBnZW5lcmF0ZWQgYnkgQ2hhcmxlcyBQcm94eSBmb3IgU1NMIFByb3h5aW5nLiBJ
ZiB0aGlzIGNlcnRpZmljYXRlIGlzIHBhcnQgb2YgYSBjZXJ0aWZpY2F0ZSBjaGFp
biwgdGhpcyBtZWFucyB0aGF0IHlvdSdyZSBicm93c2luZyB0aHJvdWdoIENoYXJs
ZXMgUHJveHkgd2l0aCBTU0wgUHJveHlpbmcgZW5hYmxlZCBmb3IgdGhpcyB3ZWJz
aXRlLiBQbGVhc2Ugc2VlIGh0dHA6Ly9jaGFybGVzcHJveHkuY29tL3NzbCBmb3Ig
bW9yZSBpbmZvcm1hdGlvbi4wDgYDVR0PAQH/BAQDAgIEMB0GA1UdDgQWBBTtSzIK
BzFSToLLgoAPM4tSPWqDEDANBgkqhkiG9w0BAQsFAAOCAQEAnB+8XuuZAtE3WE03
xIu3rHw+sYdrSvV0es/xt1L2/gnnll/W7PvK4prG62sagblbbnLECLy8AKfN/gh9
aY9i6EXxee+vVy8GC8Cmo4TIv0asmPqUXBv+ggZCRNvnT1mtCvpkjgeEwGTXjqk6
Caq1X61WDzTg/EBPpqhSX10BTFRXLufVMfC/Qy5EdpgwCOm8SZnEwqgAW62GM81L
ngl+WIM+NLX5sdtSmkuhfikNR5rRvFPIjBU1t9qP77l/24Ov5BsGjcMfk3Pjzdqy
8V17WhQGRhb/k6nzlxrxWmQ4rdNVtKLWHD9ubozsX23z6B8l1GMDzYr3VbxdMpGP
V5eiGA==
-----END CERTIFICATE-----
</code></pre>
<p>&#x7528;openssl&#x89E3;&#x6790;&#x8BC1;&#x4E66;&#xFF1A;</p>
<pre><code>openssl x509 -text -in ~/Downloads/charles-ssl-proxying-certificate.pem
</code></pre>
<p>&#x5F97;&#x5230;&#x5982;&#x4E0B;&#x8F93;&#x51FA;&#xFF1A;</p>
<pre><code>Certificate:
    Data:
        Version: 3 (0x2)
        Serial Number:
            04:00:00:00:00:01:0f:86:26:e6:0d
    Signature Algorithm: sha1WithRSAEncryption
        Issuer: OU=GlobalSign Root CA - R2, O=GlobalSign, CN=GlobalSign
        Validity
            Not Before: Dec 15 08:00:00 2006 GMT
            Not After : Dec 15 08:00:00 2021 GMT
        Subject: OU=GlobalSign Root CA - R2, O=GlobalSign, CN=GlobalSign
        Subject Public Key Info:
            Public Key Algorithm: rsaEncryption
                Public-Key: (2048 bit)
                Modulus:
                    00:a6:cf:24:0e:be:2e:6f:28:99:45:42:c4:ab:3e:
                    21:54:9b:0b:d3:7f:84:70:fa:12:b3:cb:bf:87:5f:
                    c6:7f:86:d3:b2:30:5c:d6:fd:ad:f1:7b:dc:e5:f8:
                    60:96:09:92:10:f5:d0:53:de:fb:7b:7e:73:88:ac:
                    52:88:7b:4a:a6:ca:49:a6:5e:a8:a7:8c:5a:11:bc:
                    7a:82:eb:be:8c:e9:b3:ac:96:25:07:97:4a:99:2a:
                    07:2f:b4:1e:77:bf:8a:0f:b5:02:7c:1b:96:b8:c5:
                    b9:3a:2c:bc:d6:12:b9:eb:59:7d:e2:d0:06:86:5f:
                    5e:49:6a:b5:39:5e:88:34:ec:bc:78:0c:08:98:84:
                    6c:a8:cd:4b:b4:a0:7d:0c:79:4d:f0:b8:2d:cb:21:
                    ca:d5:6c:5b:7d:e1:a0:29:84:a1:f9:d3:94:49:cb:
                    24:62:91:20:bc:dd:0b:d5:d9:cc:f9:ea:27:0a:2b:
                    73:91:c6:9d:1b:ac:c8:cb:e8:e0:a0:f4:2f:90:8b:
                    4d:fb:b0:36:1b:f6:19:7a:85:e0:6d:f2:61:13:88:
                    5c:9f:e0:93:0a:51:97:8a:5a:ce:af:ab:d5:f7:aa:
                    09:aa:60:bd:dc:d9:5f:df:72:a9:60:13:5e:00:01:
                    c9:4a:fa:3f:a4:ea:07:03:21:02:8e:82:ca:03:c2:
                    9b:8f
                Exponent: 65537 (0x10001)
        X509v3 extensions:
            X509v3 Key Usage: critical
                Certificate Sign, CRL Sign
            X509v3 Basic Constraints: critical
                CA:TRUE
            X509v3 Subject Key Identifier:
                9B:E2:07:57:67:1C:1E:C0:6A:06:DE:59:B4:9A:2D:DF:DC:19:86:2E
            X509v3 CRL Distribution Points:

                Full Name:
                  URI:http://crl.globalsign.net/root-r2.crl

            X509v3 Authority Key Identifier:
                keyid:9B:E2:07:57:67:1C:1E:C0:6A:06:DE:59:B4:9A:2D:DF:DC:19:86:2E

    Signature Algorithm: sha1WithRSAEncryption
         99:81:53:87:1c:68:97:86:91:ec:e0:4a:b8:44:0b:ab:81:ac:
         27:4f:d6:c1:b8:1c:43:78:b3:0c:9a:fc:ea:2c:3c:6e:61:1b:
         4d:4b:29:f5:9f:05:1d:26:c1:b8:e9:83:00:62:45:b6:a9:08:
         93:b9:a9:33:4b:18:9a:c2:f8:87:88:4e:db:dd:71:34:1a:c1:
         54:da:46:3f:e0:d3:2a:ab:6d:54:22:f5:3a:62:cd:20:6f:ba:
         29:89:d7:dd:91:ee:d3:5c:a2:3e:a1:5b:41:f5:df:e5:64:43:
         2d:e9:d5:39:ab:d2:a2:df:b7:8b:d0:c0:80:19:1c:45:c0:2d:
         8c:e8:f8:2d:a4:74:56:49:c5:05:b5:4f:15:de:6e:44:78:39:
         87:a8:7e:bb:f3:79:18:91:bb:f4:6f:9d:c1:f0:8c:35:8c:5d:
         01:fb:c3:6d:b9:ef:44:6d:79:46:31:7e:0a:fe:a9:82:c1:ff:
         ef:ab:6e:20:c4:50:c9:5f:9d:4d:9b:17:8c:0c:e5:01:c9:a0:
         41:6a:73:53:fa:a5:50:b4:6e:25:0f:fb:4c:18:f4:fd:52:d9:
         8e:69:b1:e8:11:0f:de:88:d8:fb:1d:49:f7:aa:de:95:cf:20:
         78:c2:60:12:db:25:40:8c:6a:fc:7e:42:38:40:64:12:f7:9e:
         81:e1:93:2e
</code></pre>
<p>&#x8F93;&#x51FA;&#x4E2D;&#x662F;&#x6CA1;&#x6709;X509v3 Authority Key Identifier&#x7684;&#x5B57;&#x6BB5;&#x7684;&#xFF0C;&#x6839;&#x636E;<a href="https://tools.ietf.org/html/rfc3280#section-4.2.1.1">RFC3280</a>&#x7684;&#x5B9A;&#x4E49;&#xFF0C;&#x53EA;&#x6709;&#x6839;&#x8BC1;&#x4E66;&#x5141;&#x8BB8;&#x7701;&#x7565;&#x8FD9;&#x4E2A;&#x5B57;&#x6BB5;&#xFF1A;</p>
<pre><code>The keyIdentifier field of the authorityKeyIdentifier extension MUST
be included in all certificates generated by conforming CAs to
facilitate certification path construction.  There is one exception;
where a CA distributes its public key in the form of a &quot;self-signed&quot;
certificate, the authority key identifier MAY be omitted. 
</code></pre>
<p>&#x6240;&#x4EE5;&#x8FD9;&#x662F;&#x4E00;&#x4E2A;&#x81EA;&#x7B7E;&#x540D;&#x7684;&#x6839;&#x8BC1;&#x4E66;&#x3002;&#x5F53;&#x7CFB;&#x7EDF;&#x4FE1;&#x4EFB;&#x4E86;&#x6839;&#x8BC1;&#x4E66;&#xFF0C;&#x90A3;&#x4E48;&#x6839;&#x8BC1;&#x4E66;&#x94FE;&#x4E0B;&#x7684;&#x6240;&#x6709;&#x5B50;&#x8BC1;&#x4E66;&#x90FD;&#x4F1A;&#x88AB;&#x8BA4;&#x4E3A;&#x5408;&#x6CD5;&#xFF0C;&#x8BC1;&#x4E66;&#x94FE;&#x7684;&#x6982;&#x5FF5;&#x4E0B;&#x9762;&#x7EC6;&#x8BF4;&#x3002;Charles&#x7684;&#x6293;&#x5305;&#x529F;&#x80FD;&#x662F;&#x901A;&#x8FC7;&#x4E2D;&#x95F4;&#x4EBA;&#x653B;&#x51FB;&#x6765;&#x5B8C;&#x6210;&#x7684;&#xFF0C;&#x6839;&#x8BC1;&#x4E66;&#x88AB;&#x4FE1;&#x4EFB;&#xFF0C;&#x90A3;&#x4E48;Charles&#x53EA;&#x8981;&#x7528;&#x4E00;&#x4E2A;&#x5B50;&#x8BC1;&#x4E66;&#x6765;&#x6B3A;&#x9A97;&#x88AB;&#x6293;&#x5305;&#x7684;&#x5BA2;&#x6237;&#x7AEF;&#xFF0C;&#x5C31;&#x80FD;&#x7ED5;&#x8FC7;TLS&#x5BF9;&#x4E2D;&#x95F4;&#x4EBA;&#x653B;&#x51FB;&#x7684;&#x9632;&#x62A4;&#x3002;<br>
&#x5728;Android 6.0&#x4E4B;&#x524D;&#xFF0C;&#x7528;&#x6237;&#x4FE1;&#x4EFB;&#x7684;CA&#x8BC1;&#x4E66;&#x4F1A;&#x88AB;&#x8BA4;&#x4E3A;&#x662F;&#x5408;&#x6CD5;&#x7684;&#xFF0C;&#x5B89;&#x88C5;&#x4E00;&#x4E2A;&#x6839;&#x8BC1;&#x4E66;&#x5C31;&#x80FD;&#x89E3;&#x5BC6;&#x6240;&#x6709;App&#x7684;HTTPS&#x6D41;&#x91CF;&#xFF0C;6.0&#x4E4B;&#x540E;&#x52A0;&#x4E86;&#x4E2A;&#x9650;&#x5236;&#xFF0C;&#x53EA;&#x6709;&#x7CFB;&#x7EDF;&#x5185;&#x7F6E;&#x7684;CA&#x8BC1;&#x4E66;&#x88AB;&#x4FE1;&#x4EFB;&#xFF0C;&#x5F00;&#x53D1;&#x4E2D;&#x7684;&#x5E94;&#x7528;&#x9700;&#x8981;&#x624B;&#x52A8;&#x4FE1;&#x4EFB;&#x7528;&#x6237;&#x6DFB;&#x52A0;&#x7684;CA&#x8BC1;&#x4E66;&#x624D;&#x884C;&#xFF0C;&#x8FD9;&#x6837;&#x5C31;&#x53EA;&#x6709;&#x624B;&#x52A8;&#x4FE1;&#x4EFB;&#x4E86;&#x8BC1;&#x4E66;&#x7684;&#x5E94;&#x7528;&#x6D41;&#x91CF;&#x80FD;&#x88AB;&#x89E3;&#x5BC6;&#xFF1A;</p>
<pre><code>&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
&lt;network-security-config&gt;
    &lt;domain-config&gt;
        &lt;domain includeSubdomains=&quot;true&quot;&gt;example.com&lt;/domain&gt;
        &lt;trust-anchors&gt;
            &lt;certificates src=&quot;@raw/my_ca&quot;/&gt;
        &lt;/trust-anchors&gt;
    &lt;/domain-config&gt;
&lt;/network-security-config&gt;
</code></pre>
<p>&#x90A3;&#x4E48;&#x6709;&#x6CA1;&#x6709;&#x5728;&#x9AD8;&#x7248;&#x672C;Android&#x4E0A;&#x5168;&#x5C40;&#x6293;&#x5305;&#x7684;&#x65B9;&#x6CD5;&#x5462;&#xFF1F;&#x8FD8;&#x771F;&#x6709;&#xFF0C;&#x5BF9;&#x4E8E;ROOT&#x8FC7;&#x7684;&#x624B;&#x673A;&#xFF0C;&#x6211;&#x4EEC;&#x53EF;&#x4EE5;&#x5BFC;&#x51FA;.0&#x683C;&#x5F0F;&#x7684;&#x8BC1;&#x4E66;&#xFF0C;&#x653E;&#x5230;&#x7CFB;&#x7EDF;&#x7684;/etc/security/cacerts/&#x76EE;&#x5F55;&#x4E0B;&#xFF0C;&#x8FD9;&#x6837;&#x5C31;&#x4F1A;&#x88AB;&#x8BA4;&#x4E3A;&#x662F;&#x7CFB;&#x7EDF;&#x5185;&#x7F6E;CA&#x8BC1;&#x4E66;&#xFF0C;&#x4ECE;&#x800C;&#x8FBE;&#x5230;&#x6293;&#x53D6;&#x6240;&#x6709;&#x5E94;&#x7528;HTTPS&#x6D41;&#x91CF;&#x7684;&#x76EE;&#x7684;&#x3002;</p>
<h1 id="tls">TLS&#x4E0E;&#x8BC1;&#x4E66;</h1>
<p>&#x5728;&#x8BB2;&#x672C;&#x6587;&#x7684;&#x4E3B;&#x9898;SSL Pinning&#x4E4B;&#x524D;&#xFF0C;&#x9700;&#x8981;&#x4ECB;&#x7ECD;&#x4E00;&#x4E9B;&#x80CC;&#x666F;&#x77E5;&#x8BC6;&#xFF0C;&#x4E0B;&#x9762;&#x51E0;&#x8282;&#x89E3;&#x91CA;&#x4E86;TLS&#x63E1;&#x624B;&#x8FC7;&#x7A0B;&#xFF0C;&#x4EE5;&#x53CA;&#x8BC1;&#x4E66;&#x7684;&#x6821;&#x9A8C;&#x8FC7;&#x7A0B;&#x3002;</p>
<h2 id="tls">TLS&#x63E1;&#x624B;</h2>
<p>&#x8FD9;&#x91CC;&#x53C8;&#x8981;&#x62FF;&#x51FA;Cloudflare&#x7684;&#x7ECF;&#x5178;&#x56FE;&#x4E86;&#xFF1A;<br>
<img src="https://github.com/shunix/BlogImages/blob/master/20170913_ssl_handshake_rsa.jpg?raw=true" alt="SSL" loading="lazy"><br>
&#x8FD9;&#x91CC;&#x63CF;&#x8FF0;&#x7684;&#x662F;TLS1.3&#x4E4B;&#x524D;&#x7684;&#x60C5;&#x51B5;&#xFF0C;&#x7EC6;&#x8282;&#x4E0D;&#x518D;&#x8D58;&#x8FF0;&#xFF0C;&#x53EF;&#x4EE5;&#x770B;&#x6211;&#x4E4B;&#x524D;&#x7684;&#x6587;&#x7AE0;&#xFF1A;<a href="/tls-handshake/">TLS&#x63E1;&#x624B;&#x8FC7;&#x7A0B;</a>&#xFF0C;&#x6211;&#x4EEC;&#x53EA;&#x9700;&#x8981;&#x6CE8;&#x610F;&#x5176;&#x4E2D;&#x4E00;&#x4E2A;&#x91CD;&#x70B9;&#xFF1A;&#x670D;&#x52A1;&#x7AEF;&#x4F1A;&#x628A;&#x81EA;&#x5DF1;&#x7684;&#x8BC1;&#x4E66;&#x53D1;&#x9001;&#x7ED9;&#x5BA2;&#x6237;&#x7AEF;&#xFF0C;&#x800C;&#x8BC1;&#x4E66;&#x4E2D;&#x5305;&#x542B;&#x4E86;&#x516C;&#x94A5;&#x4FE1;&#x606F;&#x3002;</p>
<h2 id>&#x8BC1;&#x4E66;&#x6821;&#x9A8C;</h2>
<p>&#x90A3;&#x4E48;&#x5BA2;&#x6237;&#x7AEF;&#x5F97;&#x5230;&#x8BC1;&#x4E66;&#x662F;&#x5982;&#x4F55;&#x6821;&#x9A8C;&#x8FD9;&#x4E2A;&#x8BC1;&#x4E66;&#x662F;&#x5408;&#x6CD5;&#x7684;&#x5462;&#xFF1F;&#x8FD9;&#x91CC;&#x5C31;&#x8981;&#x5F15;&#x5165;&#x8BC1;&#x4E66;&#x94FE;&#x7684;&#x6982;&#x5FF5;&#xFF0C;&#x4EE5;Google&#x4E3A;&#x4F8B;&#xFF1A;<br>
<img src="https://github.com/shunix/BlogImages/blob/master/20200921_google_certs.png?raw=true" alt="Google Certs" loading="lazy"><br>
&#x53EF;&#x4EE5;&#x770B;&#x5230;&#xFF0C;&#x8FD9;&#x91CC;&#x4E00;&#x5171;&#x662F;&#x6709;&#x4E09;&#x7EA7;&#x8BC1;&#x4E66;&#x7684;&#xFF0C;&#x81EA;&#x5E95;&#x5411;&#x4E0A;&#x5206;&#x522B;&#x88AB;&#x79F0;&#x4E3A;&#x6700;&#x7EC8;&#x5B9E;&#x4F53;&#x8BC1;&#x4E66;&#xFF0C;&#x4E2D;&#x95F4;&#x8BC1;&#x4E66;&#x548C;&#x6839;&#x8BC1;&#x4E66;&#x3002;&#x628A;&#x4E09;&#x4E2A;&#x8BC1;&#x4E66;&#x62D6;&#x51FA;&#x6765;&#xFF0C;&#x5206;&#x522B;&#x5B58;&#x6210;&#x6587;&#x4EF6;:<br>
<img src="https://github.com/shunix/BlogImages/blob/master/20200921_google_certs_list.png?raw=true" alt="Google Certs List" loading="lazy"><br>
&#x8BC1;&#x4E66;&#x90FD;&#x662F;cer&#x540E;&#x7F00;&#xFF0C;&#x6211;&#x4EEC;&#x5C1D;&#x8BD5;&#x7528;DER&#x89E3;&#x7801;&#xFF0C;&#x5148;&#x770B;&#x770B;&#x6700;&#x7EC8;&#x5B9E;&#x4F53;&#x8BC1;&#x4E66;&#xFF1A;</p>
<pre><code>openssl x509 -text -inform der -in ~/Downloads/\*.google.com.cer
</code></pre>
<p>&#x8F93;&#x51FA;&#x5982;&#x4E0B;&#x4FE1;&#x606F;&#xFF1A;</p>
<pre><code>Certificate:
    Data:
        Version: 3 (0x2)
        Serial Number:
            31:79:87:25:0f:c0:be:e8:08:00:00:00:00:56:05:ed
    Signature Algorithm: sha256WithRSAEncryption
        Issuer: C=US, O=Google Trust Services, CN=GTS CA 1O1
        Validity
            Not Before: Aug 26 08:08:49 2020 GMT
            Not After : Nov 18 08:08:49 2020 GMT
        Subject: C=US, ST=California, L=Mountain View, O=Google LLC, CN=*.google.com
        Subject Public Key Info:
            Public Key Algorithm: id-ecPublicKey
                Public-Key: (256 bit)
                pub:
                    04:8e:14:e9:f8:bb:ae:1f:c4:64:53:b7:d6:7a:76:
                    50:8b:ab:05:c6:2e:71:32:e0:3e:db:ef:1e:5a:34:
                    43:a4:74:6a:2b:52:38:75:03:f0:2d:fa:e6:da:82:
                    10:92:53:9b:a0:0e:28:ea:61:68:2b:0c:6d:df:22:
                    da:5f:14:1b:90
                ASN1 OID: prime256v1
                NIST CURVE: P-256
        X509v3 extensions:
            X509v3 Key Usage: critical
                Digital Signature
            X509v3 Extended Key Usage:
                TLS Web Server Authentication
            X509v3 Basic Constraints: critical
                CA:FALSE
            X509v3 Subject Key Identifier:
                96:65:7B:C2:08:15:03:E1:C3:F8:50:DD:8F:B6:73:65:43:DF:8C:80
            X509v3 Authority Key Identifier:
                keyid:98:D1:F8:6E:10:EB:CF:9B:EC:60:9F:18:90:1B:A0:EB:7D:09:FD:2B

            Authority Information Access:
                OCSP - URI:http://ocsp.pki.goog/gts1o1core
                CA Issuers - URI:http://pki.goog/gsr2/GTS1O1.crt

            X509v3 Subject Alternative Name:
                DNS:*.google.com, DNS:*.android.com, DNS:*.appengine.google.com, DNS:*.bdn.dev, DNS:*.cloud.google.com, DNS:*.crowdsource.google.com, DNS:*.datacompute.google.com, DNS:*.g.co, DNS:*.gcp.gvt2.com, DNS:*.gcpcdn.gvt1.com, DNS:*.ggpht.cn, DNS:*.gkecnapps.cn, DNS:*.google-analytics.com, DNS:*.google.ca, DNS:*.google.cl, DNS:*.google.co.in, DNS:*.google.co.jp, DNS:*.google.co.uk, DNS:*.google.com.ar, DNS:*.google.com.au, DNS:*.google.com.br, DNS:*.google.com.co, DNS:*.google.com.mx, DNS:*.google.com.tr, DNS:*.google.com.vn, DNS:*.google.de, DNS:*.google.es, DNS:*.google.fr, DNS:*.google.hu, DNS:*.google.it, DNS:*.google.nl, DNS:*.google.pl, DNS:*.google.pt, DNS:*.googleadapis.com, DNS:*.googleapis.cn, DNS:*.googlecnapps.cn, DNS:*.googlecommerce.com, DNS:*.googlevideo.com, DNS:*.gstatic.cn, DNS:*.gstatic.com, DNS:*.gstaticcnapps.cn, DNS:*.gvt1.com, DNS:*.gvt2.com, DNS:*.metric.gstatic.com, DNS:*.urchin.com, DNS:*.url.google.com, DNS:*.wear.gkecnapps.cn, DNS:*.youtube-nocookie.com, DNS:*.youtube.com, DNS:*.youtubeeducation.com, DNS:*.youtubekids.com, DNS:*.yt.be, DNS:*.ytimg.com, DNS:android.clients.google.com, DNS:android.com, DNS:developer.android.google.cn, DNS:developers.android.google.cn, DNS:g.co, DNS:ggpht.cn, DNS:gkecnapps.cn, DNS:goo.gl, DNS:google-analytics.com, DNS:google.com, DNS:googlecnapps.cn, DNS:googlecommerce.com, DNS:source.android.google.cn, DNS:urchin.com, DNS:www.goo.gl, DNS:youtu.be, DNS:youtube.com, DNS:youtubeeducation.com, DNS:youtubekids.com, DNS:yt.be
            X509v3 Certificate Policies:
                Policy: 2.23.140.1.2.2
                Policy: 1.3.6.1.4.1.11129.2.5.3

            X509v3 CRL Distribution Points:

                Full Name:
                  URI:http://crl.pki.goog/GTS1O1core.crl

            1.3.6.1.4.1.11129.2.4.2:
.v.....7~.b....a...{7.V..&amp;[...K.ATn...t*........G0E. .i...V.i.U....g..}&quot;..d.6.../R.V+.!..X..#.....S.}..7../.l.V=G....d....GF0M..j-u....~f.HZ
    Signature Algorithm: sha256WithRSAEncryption
         2f:de:47:43:cd:2d:0a:ed:6f:6d:3c:4b:39:0e:e6:05:17:74:
         58:a7:33:f0:a1:10:0a:52:94:55:80:52:8a:5c:a0:88:73:35:
         55:cd:d9:51:72:de:c2:96:5c:52:83:f2:ca:05:a1:72:60:06:
         8e:da:4d:80:05:6a:60:fe:60:ab:cc:dc:02:67:84:41:47:cd:
         eb:af:80:6b:ec:d5:0d:6e:56:5a:bd:00:47:d8:62:2f:4c:01:
         93:76:10:bb:16:15:ca:d4:d9:b2:92:0e:5d:96:56:06:95:c3:
         a6:d6:77:fb:97:b6:2f:66:06:7c:0c:21:91:ac:8c:84:16:61:
         40:02:a9:f1:ca:62:e3:e0:72:da:7b:ab:3f:64:27:bb:d0:ff:
         de:a0:c4:6d:a3:72:1d:bc:0e:1d:a7:6a:07:15:69:70:aa:63:
         d2:68:ed:50:d2:44:c4:21:ca:b4:ec:73:0b:0c:b2:86:17:fa:
         cd:4a:ca:57:2c:56:9d:17:10:0e:68:ce:6d:e1:00:d4:65:f1:
         11:63:9f:e4:07:d9:fb:eb:36:7e:77:bc:94:a3:c5:04:8c:ca:
         fa:ec:7a:a3:33:fb:b1:65:82:d0:2b:e7:02:29:f9:c4:91:da:
         3e:62:3e:8a:da:29:c2:91:bb:60:cf:d6:d2:f4:5b:a5:19:37:
         b1:ae:b8:7e
</code></pre>
<p>&#x4FE1;&#x606F;&#x91CF;&#x975E;&#x5E38;&#x5927;&#xFF0C;&#x6211;&#x4EEC;&#x5173;&#x6CE8;&#x51E0;&#x4E2A;&#x5173;&#x952E;&#x5B57;&#x6BB5;&#xFF1A;<br>
Signature Algorithm: sha256WithRSAEncryption&#x8868;&#x793A;&#x8BC1;&#x4E66;&#x7684;&#x7B7E;&#x540D;&#x662F;&#x5148;&#x4F7F;&#x7528;SHA256&#x505A;&#x6458;&#x8981;&#xFF0C;&#x518D;&#x5BF9;&#x6458;&#x8981;&#x505A;RSA&#x52A0;&#x5BC6;&#x751F;&#x6210;&#x7684;&#x3002;<br>
Public Key Algorithm: id-ecPublicKey&#xFF0C;&#x8868;&#x793A;&#x516C;&#x94A5;&#x7684;&#x7B97;&#x6CD5;&#x662F;ECDSA,&#x8FD9;&#x662F;&#x4E00;&#x4E2A;ECC&#x8BC1;&#x4E66;&#xFF0C;&#x76F8;&#x6BD4;RSA&#x7B97;&#x6CD5;&#xFF0C;ECDSA&#x7684;&#x8BC1;&#x4E66;&#x66F4;&#x5C0F;&#xFF0C;&#x8FD0;&#x7B97;&#x4E5F;&#x66F4;&#x5FEB;&#x3002;<br>
X509v3 Authority Key Identifier&#xFF0C;&#x4E0D;&#x9700;&#x8981;&#x5173;&#x5FC3;&#x5185;&#x5BB9;&#xFF0C;&#x6709;&#x8FD9;&#x4E2A;&#x5B57;&#x6BB5;&#x8868;&#x793A;&#x8FD9;&#x4E0D;&#x662F;&#x81EA;&#x7B7E;&#x540D;&#x7684;&#x6839;&#x8BC1;&#x4E66;&#x3002;<br>
X509v3 Subject Alternative Name&#xFF0C;&#x8FD9;&#x91CC;&#x5305;&#x542B;&#x4E86;&#x8BC1;&#x4E66;&#x9002;&#x7528;&#x7684;&#x57DF;&#x540D;&#x3002;<br>
&#x6700;&#x540E;&#x8FD8;&#x6709;&#x4E00;&#x6BB5;Signature Algorithm&#xFF0C;&#x8FD9;&#x5C31;&#x662F;&#x8BC1;&#x4E66;&#x7684;&#x7B7E;&#x540D;&#xFF0C;&#x914D;&#x5408;&#x524D;&#x9762;&#x7684;&#x8BC1;&#x4E66;&#x7B7E;&#x540D;&#x7B97;&#x6CD5;&#x53EF;&#x4EE5;&#x5B8C;&#x6210;&#x8BC1;&#x4E66;&#x94FE;&#x7684;&#x6821;&#x9A8C;&#x3002;<br>
&#x4E2D;&#x95F4;&#x8BC1;&#x4E66;&#x7684;&#x7ED3;&#x6784;&#x5927;&#x540C;&#x5C0F;&#x5F02;&#xFF0C;&#x8FD9;&#x91CC;&#x5217;&#x51FA;&#x7528;&#x4E8E;&#x6821;&#x9A8C;&#x7684;&#x5173;&#x952E;&#x4FE1;&#x606F;&#xFF1A;</p>
<pre><code>Subject Public Key Info:
            Public Key Algorithm: rsaEncryption
                Public-Key: (2048 bit)
                Modulus:
                    00:d0:18:cf:45:d4:8b:cd:d3:9c:e4:40:ef:7e:b4:
                    dd:69:21:1b:c9:cf:3c:8e:4c:75:b9:0f:31:19:84:
                    3d:9e:3c:29:ef:50:0d:10:93:6f:05:80:80:9f:2a:
                    a0:bd:12:4b:02:e1:3d:9f:58:16:24:fe:30:9f:0b:
                    74:77:55:93:1d:4b:f7:4d:e1:92:82:10:f6:51:ac:
                    0c:c3:b2:22:94:0f:34:6b:98:10:49:e7:0b:9d:83:
                    39:dd:20:c6:1c:2d:ef:d1:18:61:65:e7:23:83:20:
                    a8:23:12:ff:d2:24:7f:d4:2f:e7:44:6a:5b:4d:d7:
                    50:66:b0:af:9e:42:63:05:fb:e0:1c:c4:63:61:af:
                    9f:6a:33:ff:62:97:bd:48:d9:d3:7c:14:67:dc:75:
                    dc:2e:69:e8:f8:6d:78:69:d0:b7:10:05:b8:f1:31:
                    c2:3b:24:fd:1a:33:74:f8:23:e0:ec:6b:19:8a:16:
                    c6:e3:cd:a4:cd:0b:db:b3:a4:59:60:38:88:3b:ad:
                    1d:b9:c6:8c:a7:53:1b:fc:bc:d9:a4:ab:bc:dd:3c:
                    61:d7:93:15:98:ee:81:bd:8f:e2:64:47:20:40:06:
                    4e:d7:ac:97:e8:b9:c0:59:12:a1:49:25:23:e4:ed:
                    70:34:2c:a5:b4:63:7c:f9:a3:3d:83:d1:cd:6d:24:
                    ac:07
                Exponent: 65537 (0x10001)
</code></pre>
<p>&#x8FD9;&#x4E00;&#x6BB5;&#x7ED9;&#x51FA;&#x4E86;&#x4E2D;&#x95F4;&#x8BC1;&#x4E66;&#x7684;&#x516C;&#x94A5;&#xFF0C;&#x56E0;&#x4E3A;&#x662F;RSA&#x7B97;&#x6CD5;&#xFF0C;&#x6240;&#x4EE5;&#x8FD9;&#x91CC;&#x6709;&#x4E00;&#x4E2A;Modulus&#x548C;&#x4E00;&#x4E2A;Exponent&#x3002;&#x6700;&#x7EC8;&#x5B9E;&#x4F53;&#x8BC1;&#x4E66;&#x7684;&#x7B7E;&#x540D;&#x662F;&#x7528;&#x4E2D;&#x95F4;&#x8BC1;&#x4E66;&#x7684;&#x79C1;&#x94A5;&#x5BF9;&#x6700;&#x7EC8;&#x5B9E;&#x4F53;&#x8BC1;&#x4E66;&#x7684;&#x6458;&#x8981;&#x52A0;&#x5BC6;&#x5F97;&#x5230;&#xFF0C;&#x6240;&#x4EE5;&#x5BF9;&#x5E94;&#x7684;&#x89E3;&#x5BC6;&#x8FC7;&#x7A0B;&#x662F;&#x7528;&#x4E2D;&#x95F4;&#x8BC1;&#x4E66;&#x7684;&#x516C;&#x94A5;&#x89E3;&#x5BC6;&#x6700;&#x7EC8;&#x5B9E;&#x4F53;&#x8BC1;&#x4E66;&#x7684;&#x7B7E;&#x540D;&#xFF0C;&#x80FD;&#x5F97;&#x51FA;&#x6700;&#x7EC8;&#x5B9E;&#x4F53;&#x8BC1;&#x4E66;&#x7684;&#x6458;&#x8981;&#xFF0C;&#x5982;&#x679C;&#x80FD;&#x89E3;&#x5BC6;&#x6210;&#x529F;&#xFF0C;&#x5C31;&#x80FD;&#x786E;&#x8BA4;&#x6700;&#x7EC8;&#x5B9E;&#x4F53;&#x8BC1;&#x4E66;&#x786E;&#x5B9E;&#x662F;&#x7531;&#x4E2D;&#x95F4;&#x8BC1;&#x4E66;&#x7B7E;&#x540D;&#x7684;&#xFF0C;&#x518D;&#x5BF9;&#x6700;&#x7EC8;&#x5B9E;&#x4F53;&#x8BC1;&#x4E66;&#x505A;&#x4E00;&#x6B21;&#x6458;&#x8981;&#xFF0C;&#x548C;&#x89E3;&#x5BC6;&#x51FA;&#x5F97;&#x6458;&#x8981;&#x6BD4;&#x5BF9;&#xFF0C;&#x5982;&#x679C;&#x4E00;&#x81F4;&#x5373;&#x53EF;&#x786E;&#x8BA4;&#x8BC1;&#x4E66;&#x6CA1;&#x7528;&#x88AB;&#x7BE1;&#x6539;&#x8FC7;&#x3002;<br>
&#x6211;&#x4EEC;&#x624B;&#x52A8;&#x5B9E;&#x73B0;&#x4E00;&#x4E0B;&#x8FD9;&#x4E2A;&#x8FC7;&#x7A0B;&#xFF1A;<br>
&#x5DF2;&#x77E5;&#x6307;&#x6570;&#xFF0C;&#x6A21;&#x548C;&#x5BC6;&#x6587;&#xFF0C;&#x6211;&#x4EEC;&#x9700;&#x8981;&#x8FD8;&#x539F;&#x51FA;&#x539F;&#x6587;&#xFF0C;&#x6839;&#x636E;RSA&#x7B97;&#x6CD5;&#xFF0C;&#x8BA1;&#x7B97;&#x539F;&#x6587;&#x7684;&#x7B97;&#x6CD5;&#x5982;&#x4E0B;&#xFF0C;&#x5176;&#x4E2D;m&#x662F;&#x660E;&#x6587;&#xFF0C;c&#x662F;&#x5BC6;&#x6587;&#xFF0C;e&#x662F;&#x6307;&#x6570;&#xFF0C;n&#x662F;&#x6A21;&#xFF1A;</p>
<pre><code>m = c ^ e (mod n)
</code></pre>
<p>&#x4EE3;&#x5165;&#x4E0A;&#x9762;&#x8BC1;&#x4E66;&#x91CC;&#x7684;&#x503C;&#xFF1A;</p>
<pre><code>&gt;&gt;&gt; n = 0x00d018cf45d48bcdd39ce440ef7eb4dd69211bc9cf3c8e4c75b90f3119843d9e3c29ef500d10936f0580809f2aa0bd124b02e13d9f581624fe309f0b747755931d4bf74de1928210f651ac0cc3b222940f346b981049e70b9d8339dd20c61c2defd1186165e7238320a82312ffd2247fd42fe7446a5b4dd75066b0af9e426305fbe01cc46361af9f6a33ff6297bd48d9d37c1467dc75dc2e69e8f86d7869d0b71005b8f131c23b24fd1a3374f823e0ec6b198a16c6e3cda4cd0bdbb3a4596038883bad1db9c68ca7531bfcbcd9a4abbcdd3c61d7931598ee81bd8fe264472040064ed7ac97e8b9c05912a1492523e4ed70342ca5b4637cf9a33d83d1cd6d24ac07
&gt;&gt;&gt; e = 65537
&gt;&gt;&gt; c = 0x2fde4743cd2d0aed6f6d3c4b390ee605177458a733f0a1100a52945580528a5ca088733555cdd95172dec2965c5283f2ca05a17260068eda4d80056a60fe60abccdc0267844147cdebaf806becd50d6e565abd0047d8622f4c01937610bb1615cad4d9b2920e5d96560695c3a6d677fb97b62f66067c0c2191ac8c8416614002a9f1ca62e3e072da7bab3f6427bbd0ffdea0c46da3721dbc0e1da76a07156970aa63d268ed50d244c421cab4ec730b0cb28617facd4aca572c569d17100e68ce6de100d465f111639fe407d9fbeb367e77bc94a3c5048ccafaec7aa333fbb16582d02be70229f9c491da3e623e8ada29c291bb60cfd6d2f45ba51937b1aeb87e
&gt;&gt;&gt; pow(c, e, n)
986236757547332986472011617696226561292849812918563355472727826767720188564083584387121625107510786855734801053524719833194566624465665316622563244215340671405971599343902468620306327831715457360719532421388780770165778156818229863337344187575566725786793391480600129482653072861971002459947277805295727097226389568776499707662505334062639449916265137796823793276300221537201727072401742985542559596685092673521228140822200236743113743661549252453726123450722876929538747702356573783116197523966334991563351853851212597377279504828784763247643211048750059383511539240076118611220389103205312907651075225923933445
&gt;&gt;&gt; print(&apos;0x%x&apos; % pow(c, e, n))
0x1ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff003031300d060960864801650304020105000420cd55ba8e69bcc9a1c2aaba552982abd5519051f5708cb6f9885cd3a7d28cd505
</code></pre>
<p>&#x6700;&#x540E;&#x8FD9;&#x4E00;&#x6BB5;&#x5BC6;&#x6587;&#x5C31;&#x662F;&#x6700;&#x7EC8;&#x5B9E;&#x4F53;&#x8BC1;&#x4E66;&#x7684;&#x6458;&#x8981;&#xFF0C;&#x6211;&#x4EEC;&#x518D;&#x7528;openssl&#x624B;&#x52A8;&#x7B97;&#x4E00;&#x6B21;&#x6458;&#x8981;&#xFF0C;&#x770B;&#x662F;&#x5426;&#x4E00;&#x81F4;&#x3002;&#x5148;&#x628A;&#x8BC1;&#x4E66;&#x8F6C;&#x6362;&#x6210;ANS.1&#x683C;&#x5F0F;&#xFF0C;&#x8FD9;&#x662F;&#x4E00;&#x79CD;&#x548C;protobuffer&#x5F88;&#x76F8;&#x4F3C;&#x7684;&#x63CF;&#x8FF0;&#xFF0C;&#x90FD;&#x662F;tag, length, value&#x7684;&#x5F62;&#x5F0F;&#x3002;</p>
<pre><code>openssl asn1parse -inform der -in ~/Downloads/\*.google.com.cer
</code></pre>
<p>&#x8F93;&#x51FA;&#x5982;&#x4E0B;&#xFF1A;</p>
<pre><code>    0:d=0  hl=4 l=2416 cons: SEQUENCE
    4:d=1  hl=4 l=2136 cons: SEQUENCE
    8:d=2  hl=2 l=   3 cons: cont [ 0 ]
   10:d=3  hl=2 l=   1 prim: INTEGER           :02
   13:d=2  hl=2 l=  16 prim: INTEGER           :317987250FC0BEE808000000005605ED
   31:d=2  hl=2 l=  13 cons: SEQUENCE
   33:d=3  hl=2 l=   9 prim: OBJECT            :sha256WithRSAEncryption
   44:d=3  hl=2 l=   0 prim: NULL
   46:d=2  hl=2 l=  66 cons: SEQUENCE
   48:d=3  hl=2 l=  11 cons: SET
   50:d=4  hl=2 l=   9 cons: SEQUENCE
   52:d=5  hl=2 l=   3 prim: OBJECT            :countryName
   57:d=5  hl=2 l=   2 prim: PRINTABLESTRING   :US
   61:d=3  hl=2 l=  30 cons: SET
   63:d=4  hl=2 l=  28 cons: SEQUENCE
   65:d=5  hl=2 l=   3 prim: OBJECT            :organizationName
   70:d=5  hl=2 l=  21 prim: PRINTABLESTRING   :Google Trust Services
   93:d=3  hl=2 l=  19 cons: SET
   95:d=4  hl=2 l=  17 cons: SEQUENCE
   97:d=5  hl=2 l=   3 prim: OBJECT            :commonName
  102:d=5  hl=2 l=  10 prim: PRINTABLESTRING   :GTS CA 1O1
  114:d=2  hl=2 l=  30 cons: SEQUENCE
  116:d=3  hl=2 l=  13 prim: UTCTIME           :200826080849Z
  131:d=3  hl=2 l=  13 prim: UTCTIME           :201118080849Z
  146:d=2  hl=2 l= 102 cons: SEQUENCE
  148:d=3  hl=2 l=  11 cons: SET
  150:d=4  hl=2 l=   9 cons: SEQUENCE
  152:d=5  hl=2 l=   3 prim: OBJECT            :countryName
  157:d=5  hl=2 l=   2 prim: PRINTABLESTRING   :US
  161:d=3  hl=2 l=  19 cons: SET
  163:d=4  hl=2 l=  17 cons: SEQUENCE
  165:d=5  hl=2 l=   3 prim: OBJECT            :stateOrProvinceName
  170:d=5  hl=2 l=  10 prim: PRINTABLESTRING   :California
  182:d=3  hl=2 l=  22 cons: SET
  184:d=4  hl=2 l=  20 cons: SEQUENCE
  186:d=5  hl=2 l=   3 prim: OBJECT            :localityName
  191:d=5  hl=2 l=  13 prim: PRINTABLESTRING   :Mountain View
  206:d=3  hl=2 l=  19 cons: SET
  208:d=4  hl=2 l=  17 cons: SEQUENCE
  210:d=5  hl=2 l=   3 prim: OBJECT            :organizationName
  215:d=5  hl=2 l=  10 prim: PRINTABLESTRING   :Google LLC
  227:d=3  hl=2 l=  21 cons: SET
  229:d=4  hl=2 l=  19 cons: SEQUENCE
  231:d=5  hl=2 l=   3 prim: OBJECT            :commonName
  236:d=5  hl=2 l=  12 prim: UTF8STRING        :*.google.com
  250:d=2  hl=2 l=  89 cons: SEQUENCE
  252:d=3  hl=2 l=  19 cons: SEQUENCE
  254:d=4  hl=2 l=   7 prim: OBJECT            :id-ecPublicKey
  263:d=4  hl=2 l=   8 prim: OBJECT            :prime256v1
  273:d=3  hl=2 l=  66 prim: BIT STRING
  341:d=2  hl=4 l=1799 cons: cont [ 3 ]
  345:d=3  hl=4 l=1795 cons: SEQUENCE
  349:d=4  hl=2 l=  14 cons: SEQUENCE
  351:d=5  hl=2 l=   3 prim: OBJECT            :X509v3 Key Usage
  356:d=5  hl=2 l=   1 prim: BOOLEAN           :255
  359:d=5  hl=2 l=   4 prim: OCTET STRING      [HEX DUMP]:03020780
  365:d=4  hl=2 l=  19 cons: SEQUENCE
  367:d=5  hl=2 l=   3 prim: OBJECT            :X509v3 Extended Key Usage
  372:d=5  hl=2 l=  12 prim: OCTET STRING      [HEX DUMP]:300A06082B06010505070301
  386:d=4  hl=2 l=  12 cons: SEQUENCE
  388:d=5  hl=2 l=   3 prim: OBJECT            :X509v3 Basic Constraints
  393:d=5  hl=2 l=   1 prim: BOOLEAN           :255
  396:d=5  hl=2 l=   2 prim: OCTET STRING      [HEX DUMP]:3000
  400:d=4  hl=2 l=  29 cons: SEQUENCE
  402:d=5  hl=2 l=   3 prim: OBJECT            :X509v3 Subject Key Identifier
  407:d=5  hl=2 l=  22 prim: OCTET STRING      [HEX DUMP]:041496657BC2081503E1C3F850DD8FB6736543DF8C80
  431:d=4  hl=2 l=  31 cons: SEQUENCE
  433:d=5  hl=2 l=   3 prim: OBJECT            :X509v3 Authority Key Identifier
  438:d=5  hl=2 l=  24 prim: OCTET STRING      [HEX DUMP]:3016801498D1F86E10EBCF9BEC609F18901BA0EB7D09FD2B
  464:d=4  hl=2 l= 104 cons: SEQUENCE
  466:d=5  hl=2 l=   8 prim: OBJECT            :Authority Information Access
  476:d=5  hl=2 l=  92 prim: OCTET STRING      [HEX DUMP]:305A302B06082B06010505073001861F687474703A2F2F6F6373702E706B692E676F6F672F677473316F31636F7265302B06082B06010505073002861F687474703A2F2F706B692E676F6F672F677372322F475453314F312E637274
  570:d=4  hl=4 l=1218 cons: SEQUENCE
  574:d=5  hl=2 l=   3 prim: OBJECT            :X509v3 Subject Alternative Name
  579:d=5  hl=4 l=1209 prim: OCTET STRING      [HEX DUMP]:308204B5820C2A2E676F6F676C652E636F6D820D2A2E616E64726F69642E636F6D82162A2E617070656E67696E652E676F6F676C652E636F6D82092A2E62646E2E64657682122A2E636C6F75642E676F6F676C652E636F6D82182A2E63726F7764736F757263652E676F6F676C652E636F6D82182A2E64617461636F6D707574652E676F6F676C652E636F6D82062A2E672E636F820E2A2E6763702E677674322E636F6D82112A2E67637063646E2E677674312E636F6D820A2A2E67677068742E636E820E2A2E676B65636E617070732E636E82162A2E676F6F676C652D616E616C79746963732E636F6D820B2A2E676F6F676C652E6361820B2A2E676F6F676C652E636C820E2A2E676F6F676C652E636F2E696E820E2A2E676F6F676C652E636F2E6A70820E2A2E676F6F676C652E636F2E756B820F2A2E676F6F676C652E636F6D2E6172820F2A2E676F6F676C652E636F6D2E6175820F2A2E676F6F676C652E636F6D2E6272820F2A2E676F6F676C652E636F6D2E636F820F2A2E676F6F676C652E636F6D2E6D78820F2A2E676F6F676C652E636F6D2E7472820F2A2E676F6F676C652E636F6D2E766E820B2A2E676F6F676C652E6465820B2A2E676F6F676C652E6573820B2A2E676F6F676C652E6672820B2A2E676F6F676C652E6875820B2A2E676F6F676C652E6974820B2A2E676F6F676C652E6E6C820B2A2E676F6F676C652E706C820B2A2E676F6F676C652E707482122A2E676F6F676C656164617069732E636F6D820F2A2E676F6F676C65617069732E636E82112A2E676F6F676C65636E617070732E636E82142A2E676F6F676C65636F6D6D657263652E636F6D82112A2E676F6F676C65766964656F2E636F6D820C2A2E677374617469632E636E820D2A2E677374617469632E636F6D82122A2E67737461746963636E617070732E636E820A2A2E677674312E636F6D820A2A2E677674322E636F6D82142A2E6D65747269632E677374617469632E636F6D820C2A2E75726368696E2E636F6D82102A2E75726C2E676F6F676C652E636F6D82132A2E776561722E676B65636E617070732E636E82162A2E796F75747562652D6E6F636F6F6B69652E636F6D820D2A2E796F75747562652E636F6D82162A2E796F7574756265656475636174696F6E2E636F6D82112A2E796F75747562656B6964732E636F6D82072A2E79742E6265820B2A2E7974696D672E636F6D821A616E64726F69642E636C69656E74732E676F6F676C652E636F6D820B616E64726F69642E636F6D821B646576656C6F7065722E616E64726F69642E676F6F676C652E636E821C646576656C6F706572732E616E64726F69642E676F6F676C652E636E8204672E636F820867677068742E636E820C676B65636E617070732E636E8206676F6F2E676C8214676F6F676C652D616E616C79746963732E636F6D820A676F6F676C652E636F6D820F676F6F676C65636E617070732E636E8212676F6F676C65636F6D6D657263652E636F6D8218736F757263652E616E64726F69642E676F6F676C652E636E820A75726368696E2E636F6D820A7777772E676F6F2E676C8208796F7574752E6265820B796F75747562652E636F6D8214796F7574756265656475636174696F6E2E636F6D820F796F75747562656B6964732E636F6D820579742E6265
 1792:d=4  hl=2 l=  33 cons: SEQUENCE
 1794:d=5  hl=2 l=   3 prim: OBJECT            :X509v3 Certificate Policies
 1799:d=5  hl=2 l=  26 prim: OCTET STRING      [HEX DUMP]:30183008060667810C010202300C060A2B06010401D679020503
 1827:d=4  hl=2 l=  51 cons: SEQUENCE
 1829:d=5  hl=2 l=   3 prim: OBJECT            :X509v3 CRL Distribution Points
 1834:d=5  hl=2 l=  44 prim: OCTET STRING      [HEX DUMP]:302A3028A026A0248622687474703A2F2F63726C2E706B692E676F6F672F475453314F31636F72652E63726C
 1880:d=4  hl=4 l= 260 cons: SEQUENCE
 1884:d=5  hl=2 l=  10 prim: OBJECT            :1.3.6.1.4.1.11129.2.4.2
 1896:d=5  hl=3 l= 245 prim: OCTET STRING      [HEX DUMP]:0481F200F0007600B21E05CC8BA2CD8A204E8766F92BB98A2520676BDAFA70E7B249532DEF8B905E000001742A06F9BD000004030047304502205BB262C173701DC2F4D182C34760FA693875B409B650DA2DBE966D80CB6EE9C8022100CFD52D39644158ED44F23ABE9B4746304D8CAB6A2D75DA92F0187E6688485A0D007600E712F2B0377E1A62FB8EC90C6184F1EA7B37CB561D11265BF3E0F34BF241546E000001742A06F9D2000004030047304502200B69DB8E9756FB698955FA04BF8467C80E7D22C2F364CD36DACDD72F52D1562B022100925882AA2314AAB3009F53A47D93CE377FCB2FCA6C1E563D4716ACEBF264E087
 2144:d=1  hl=2 l=  13 cons: SEQUENCE
 2146:d=2  hl=2 l=   9 prim: OBJECT            :sha256WithRSAEncryption
 2157:d=2  hl=2 l=   0 prim: NULL
 2159:d=1  hl=4 l= 257 prim: BIT STRING
</code></pre>
<p>&#x518D;&#x770B;&#x770B;<a href="https://www.ietf.org/rfc/rfc5280.txt">RFC5280</a>&#x7684;&#x5B9A;&#x4E49;&#xFF1A;</p>
<pre><code>Certificate  ::=  SEQUENCE  {
        tbsCertificate       TBSCertificate,
        signatureAlgorithm   AlgorithmIdentifier,
        signatureValue       BIT STRING  }

   TBSCertificate  ::=  SEQUENCE  {
        version         [0]  EXPLICIT Version DEFAULT v1,
        serialNumber         CertificateSerialNumber,
        signature            AlgorithmIdentifier,
        issuer               Name,
        validity             Validity,
        subject              Name,
        subjectPublicKeyInfo SubjectPublicKeyInfo,
        issuerUniqueID  [1]  IMPLICIT UniqueIdentifier OPTIONAL,
                             -- If present, version MUST be v2 or v3
</code></pre>
<p>&#x7B2C;&#x4E8C;&#x884C;&#x5C31;&#x662F;TBSCertificate&#x7684;&#x4F4D;&#x7F6E;&#x548C;&#x957F;&#x5EA6;&#xFF0C;&#x771F;&#x6B63;&#x7528;&#x6765;&#x8BA1;&#x7B97;&#x6458;&#x8981;&#x7684;&#x90E8;&#x5206;&#xFF0C;&#x504F;&#x79FB;&#x662F;4&#xFF0C;hl=4&#x8868;&#x793A;header&#x957F;&#x5EA6;&#x662F;4&#xFF0C;l=2136&#x8868;&#x793A;&#x5185;&#x5BB9;&#x957F;&#x5EA6;&#x662F;2136&#xFF0C;&#x603B;&#x957F;&#x5EA6;&#x662F;2140&#xFF0C;&#x6211;&#x4EEC;&#x7528;dd&#x63D0;&#x53D6;&#x51FA;&#x8FD9;&#x90E8;&#x5206;&#xFF0C;&#x5E76;&#x5BF9;&#x8F93;&#x51FA;&#x7ED3;&#x679C;&#x505A;SHA256&#x6458;&#x8981;&#xFF1A;</p>
<pre><code>dd if=/Users/shunix/Downloads/\*.google.com.cer of=/Users/shunix/tmp/tbs skip=4 bs=1 count=2140
openssl dgst -sha256 ~/tmp/tbs
</code></pre>
<p>&#x8F93;&#x51FA;&#x5982;&#x4E0B;&#xFF1A;</p>
<pre><code>SHA256(/Users/shunix/tmp/tbs)= cd55ba8e69bcc9a1c2aaba552982abd5519051f5708cb6f9885cd3a7d28cd505
</code></pre>
<p>&#x800C;&#x4E0A;&#x9762;&#x6211;&#x4EEC;&#x7528;&#x516C;&#x94A5;&#x89E3;&#x51FA;&#x6765;&#x7684;&#x6458;&#x8981;&#x53BB;&#x6389;&#x524D;&#x9762;&#x7684;</p>
<pre><code>0x1ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff003031300d060960864801650304020105000420
</code></pre>
<p>&#x6700;&#x540E;&#x7ED3;&#x679C;&#x4E5F;&#x662F;cd55ba8e69bcc9a1c2aaba552982abd5519051f5708cb6f9885cd3a7d28cd505&#xFF0C;&#x4E8C;&#x8005;&#x5B8C;&#x5168;&#x4E00;&#x81F4;&#xFF0C;&#x8BF4;&#x660E;&#x6700;&#x7EC8;&#x5B9E;&#x4F53;&#x8BC1;&#x4E66;&#x6CA1;&#x6709;&#x88AB;&#x7BE1;&#x6539;&#x8FC7;&#x3002;<br>
&#x800C;&#x4E2D;&#x95F4;&#x8BC1;&#x4E66;&#x548C;&#x6839;&#x8BC1;&#x4E66;&#x7684;&#x6821;&#x9A8C;&#x4E5F;&#x662F;&#x540C;&#x6837;&#x7684;&#x8FC7;&#x7A0B;&#xFF0C;&#x8FD9;&#x91CC;&#x5C31;&#x4E0D;&#x8D58;&#x8FF0;&#x3002;&#x6839;&#x8BC1;&#x4E66;&#x662F;&#x81EA;&#x7B7E;&#x540D;&#x7684;&#xFF0C;&#x751A;&#x81F3;&#x90FD;&#x53EF;&#x4EE5;&#x4E0D;&#x7528;&#x7B7E;&#x540D;&#xFF0C;&#x56E0;&#x4E3A;&#x6839;&#x8BC1;&#x4E66;&#x662F;&#x5185;&#x7F6E;&#x5230;&#x7CFB;&#x7EDF;&#x91CC;&#x7684;&#x3002;<br>
CA&#x4E4B;&#x6240;&#x4EE5;&#x4E0D;&#x76F4;&#x63A5;&#x4ECE;&#x6839;&#x8BC1;&#x4E66;&#x53D1;&#x5E03;&#x6700;&#x7EC8;&#x5B9E;&#x4F53;&#x8BC1;&#x4E66;&#x662F;&#x56E0;&#x4E3A;&#x8FD9;&#x6837;&#x98CE;&#x9669;&#x592A;&#x5927;&#xFF0C;&#x4E00;&#x65E6;&#x51FA;&#x73B0;&#x9519;&#x8BEF;&#x53D1;&#x5E03;&#x5BB9;&#x6613;&#x5BFC;&#x81F4;&#x6839;&#x8BC1;&#x4E66;&#x4E0D;&#x53D7;&#x4FE1;&#x4EFB;&#xFF0C;&#x6240;&#x4EE5;CA&#x4F1A;&#x4ECE;&#x6839;&#x8BC1;&#x4E66;&#x53D1;&#x5E03;&#x4E2D;&#x95F4;&#x8BC1;&#x4E66;&#xFF0C;&#x518D;&#x4ECE;&#x4E2D;&#x95F4;&#x8BC1;&#x4E66;&#x53D1;&#x5E03;&#x6700;&#x7EC8;&#x5B9E;&#x4F53;&#x8BC1;&#x4E66;&#xFF0C;&#x5B8C;&#x6210;&#x81EA;&#x6211;&#x9694;&#x79BB;&#x3002;&#x5F53;&#x7136;&#xFF0C;&#x6839;&#x8BC1;&#x4E66;&#x4E5F;&#x662F;&#x6709;&#x4E0D;&#x88AB;&#x4FE1;&#x4EFB;&#x7684;&#x5148;&#x4F8B;&#x7684;&#xFF0C;&#x6BD4;&#x5982;Firefox&#x548C;Chrome&#x5728;2015&#x5E74;&#x79FB;&#x9664;&#x4E86;&#x5BF9;CNNIC&#x6839;&#x8BC1;&#x4E66;&#x7684;&#x4FE1;&#x4EFB;&#xFF0C;&#x5177;&#x4F53;&#x539F;&#x56E0;&#x5C31;&#x4E0D;&#x7EC6;&#x8BB2;&#x4E86;&#x3002;</p>
<h1 id="sslpinning">SSL Pinning</h1>
<p>&#x7EFC;&#x4E0A;&#x6240;&#x8FF0;&#xFF0C;&#x6709;&#x51E0;&#x79CD;&#x60C5;&#x51B5;SSL&#x662F;&#x65E0;&#x6CD5;&#x4FDD;&#x8BC1;&#x5B89;&#x5168;&#x7684;&#xFF1A;</p>
<ol>
<li>&#x67D0;&#x4E9B;wifi&#x6216;&#x8005;&#x7F51;&#x7AD9;&#x8981;&#x6C42;&#x88C5;&#x4E2A;&#x6839;&#x8BC1;&#x4E66;&#x624D;&#x80FD;&#x7EE7;&#x7EED;&#x4F7F;&#x7528;&#xFF0C;&#x6BD4;&#x5982;&#x67D0;&#x8BA2;&#x7968;&#x7F51;&#x7AD9;</li>
<li>&#x88AB;&#x4FE1;&#x4EFB;&#x7684;CA&#x968F;&#x610F;&#x53D1;&#x5E03;&#x8BC1;&#x4E66;&#xFF0C;&#x6BD4;&#x5982;&#x8D5B;&#x95E8;&#x94C1;&#x514B;&#xFF0C;17&#x5E74;&#x5C45;&#x7136;&#x53D1;&#x5E03;&#x4E86;example.com&#x7684;&#x8BC1;&#x4E66;&#xFF0C;&#x633A;&#x7F3A;&#x5FB7;&#x7684;</li>
</ol>
<p>&#x6240;&#x4EE5;&#x5BA2;&#x6237;&#x7AEF;&#x63D0;&#x4F9B;&#x4E86;&#x4E00;&#x79CD;&#x989D;&#x5916;&#x7684;&#x673A;&#x5236;&#x6765;&#x4FDD;&#x8BC1;HTTPS&#x901A;&#x4FE1;&#x7684;&#x5B89;&#x5168;&#xFF0C;SSL Pinning&#xFF0C;SSL Pinning&#x53C8;&#x53EF;&#x4EE5;&#x7EC6;&#x5206;&#x4E3A;Certificate Pinning&#x548C;Public Key Pinning&#x3002;</p>
<h2 id="certificatepinning">Certificate Pinning</h2>
<p>Certificate Pinning&#x4E5F;&#x5C31;&#x662F;&#x8BC1;&#x4E66;&#x9501;&#x5B9A;&#xFF0C;&#x7B80;&#x5355;&#x6765;&#x8BF4;&#x5C31;&#x662F;&#x628A;&#x8BC1;&#x4E66;&#x6587;&#x4EF6;&#x6253;&#x5305;&#x8FDB;&#x5B89;&#x88C5;&#x5305;&#xFF0C;&#x901A;&#x8FC7;&#x52A0;&#x8F7D;&#x672C;&#x5730;&#x8BC1;&#x4E66;&#x81EA;&#x5B9A;&#x4E49;TrustManager&#xFF0C;&#x8FDB;&#x800C;&#x521B;&#x5EFA;&#x81EA;&#x5B9A;&#x4E49;&#x7684;SSLSocketFactory&#x6765;&#x5B8C;&#x6210;&#x7684;&#xFF0C;&#x8FD9;&#x91CC;&#x8D34;&#x4E00;&#x4E9B;&#x5173;&#x952E;&#x4EE3;&#x7801;&#xFF1A;</p>
<pre><code>fun loadCertificate(): Certificate {
    // &#x5047;&#x8BBE;&#x8BC1;&#x4E66;&#x653E;&#x5728;assets&#x4E0B;
    return BaseApplication.instance.assets
        .open(&quot;shunix.cert&quot;).use { input -&gt;
        CertificateFactory.getInstance(&quot;X.509&quot;).generateCertificate(input)
    }
}

fun getTrustManager(): TrustManager {
    val keyStore = KeyStore.getInstance(KeyStore.getDefaultType()).apply {
        setCertificateEntry(&quot;shunix&quot;, loadCertificate())
    }
    return TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()).run {
        init(keyStore)
        trustManagers[0]
    }
}

fun getSSLSocketFactory(): SSLSocketFactory {
    val sslContext = SSLContext.getInstance(&quot;TLS&quot;).apply {
        init(null, arrayOf(getTrustManager()), null)
    }
    return sslContext.socketFactory
}
</code></pre>
<h3 id="fallback">fallback&#x7B56;&#x7565;</h3>
<p>&#x5185;&#x7F6E;&#x8BC1;&#x4E66;&#x7684;&#x65B9;&#x6848;&#x5B58;&#x5728;&#x4E00;&#x4E2A;&#x95EE;&#x9898;&#xFF0C;&#x8BC1;&#x4E66;&#x662F;&#x4F1A;&#x8FC7;&#x671F;&#x7684;&#xFF0C;&#x4E00;&#x822C;&#x6700;&#x7EC8;&#x5B9E;&#x4F53;&#x8BC1;&#x4E66;&#x4E5F;&#x5C31;&#x662F;&#x4E00;&#x5E74;&#x7684;&#x6709;&#x6548;&#x671F;&#xFF0C;&#x800C;&#x4E2D;&#x95F4;&#x8BC1;&#x4E66;&#x548C;&#x6839;&#x8BC1;&#x4E66;&#x6709;&#x6548;&#x671F;&#x90FD;&#x662F;10&#x5E74;&#x5DE6;&#x53F3;&#xFF0C;&#x8D85;&#x8FC7;&#x7EDD;&#x5927;&#x591A;&#x6570;&#x5E94;&#x7528;&#x7684;&#x751F;&#x547D;&#x5468;&#x671F;&#x4E86;&#xFF0C;&#x6240;&#x4EE5;&#x4E00;&#x4E2A;&#x6BD4;&#x8F83;&#x7B80;&#x5355;&#x7684;&#x505A;&#x6CD5;&#x662F;&#x540C;&#x65F6;&#x5185;&#x7F6E;&#x4E2D;&#x95F4;&#x8BC1;&#x4E66;&#x6216;&#x8005;&#x6839;&#x8BC1;&#x4E66;&#x4F5C;&#x4E3A;&#x5B50;&#x8BC1;&#x4E66;&#x8FC7;&#x671F;&#x7684;&#x5E94;&#x5BF9;&#x65B9;&#x6848;&#x3002;&#x4E2D;&#x95F4;&#x8BC1;&#x4E66;&#x548C;&#x6839;&#x8BC1;&#x4E66;&#x4E00;&#x822C;&#x90FD;&#x662F;&#x540C;&#x4E00;&#x4E2A;&#x673A;&#x6784;&#x7684;&#xFF0C;&#x6240;&#x4EE5;&#x9009;&#x54EA;&#x4E00;&#x4E2A;&#x5E76;&#x6CA1;&#x6709;&#x672C;&#x8D28;&#x7684;&#x533A;&#x522B;&#xFF0C;&#x4F46;&#x662F;&#x8FD9;&#x6837;&#x5728;&#x5B89;&#x5168;&#x6027;&#x4E0A;&#x4F1A;&#x6709;&#x4E00;&#x5B9A;&#x7684;&#x59A5;&#x534F;&#xFF0C;&#x53EF;&#x4EE5;&#x53C2;&#x8003;&#x524D;&#x9762;&#x63D0;&#x5230;&#x7684;&#x8D5B;&#x95E8;&#x94C1;&#x514B;&#x548C;CNNIC&#x8BC1;&#x4E66;&#xFF0C;&#x5F53;&#x6839;&#x8BC1;&#x4E66;&#x4E0D;&#x88AB;&#x4FE1;&#x4EFB;&#xFF0C;&#x4E00;&#x6837;&#x4F1A;&#x51FA;&#x95EE;&#x9898;&#xFF0C;&#x8FD8;&#x6709;&#x5C31;&#x662F;&#x5982;&#x679C;&#x66F4;&#x6362;&#x8BC1;&#x4E66;&#x7684;CA&#x4E5F;&#x662F;&#x505A;&#x4E0D;&#x5230;&#x7684;&#xFF0C;&#x5C40;&#x9650;&#x6027;&#x5F88;&#x5927;&#x3002;<br>
&#x90A3;&#x4E48;&#x80FD;&#x4E0D;&#x80FD;&#x53EA;&#x5185;&#x7F6E;&#x6700;&#x7EC8;&#x5B9E;&#x4F53;&#x8BC1;&#x4E66;&#xFF0C;&#x540C;&#x65F6;&#x80FD;&#x89E3;&#x51B3;&#x6709;&#x6548;&#x671F;&#x7684;&#x95EE;&#x9898;&#x5462;&#xFF1F;&#x5F88;&#x81EA;&#x7136;&#x5730;&#x4F1A;&#x60F3;&#x5230;&#x52A8;&#x6001;&#x66F4;&#x65B0;&#x672C;&#x5730;&#x8BC1;&#x4E66;&#xFF0C;&#x90A3;&#x5C31;&#x5E26;&#x6765;&#x4E86;&#x53E6;&#x4E00;&#x4E2A;&#x95EE;&#x9898;&#xFF0C;&#x5982;&#x4F55;&#x4FDD;&#x8BC1;&#x672C;&#x5730;&#x8BC1;&#x4E66;&#x66F4;&#x65B0;&#x7684;&#x5B89;&#x5168;&#x6027;&#x5462;&#xFF1F;&#x8FD9;&#x662F;&#x4E00;&#x4E2A;&#x9E21;&#x751F;&#x86CB;&#x86CB;&#x751F;&#x9E21;&#x7684;&#x95EE;&#x9898;&#xFF0C;&#x5176;&#x5B9E;&#x4E0D;&#x8BB2;&#x7A76;&#x70B9;&#xFF0C;&#x66F4;&#x65B0;&#x8BC1;&#x4E66;&#x7684;&#x8BF7;&#x6C42;&#x53EF;&#x4EE5;&#x76F4;&#x63A5;&#x8D70;&#x6CA1;&#x6709;&#x8BC1;&#x4E66;&#x9501;&#x5B9A;&#x7684;HTTPS&#x5B8C;&#x6210;&#xFF0C;&#x56E0;&#x4E3A;HTTPS&#x88AB;&#x52AB;&#x6301;&#x672C;&#x8EAB;&#x5C31;&#x662F;&#x5C0F;&#x6982;&#x7387;&#x60C5;&#x51B5;&#x3002;&#x5982;&#x679C;&#x8FFD;&#x6C42;&#x5B8C;&#x7F8E;&#x7684;&#x8BDD;&#xFF0C;&#x6709;&#x4E00;&#x4E2A;&#x6BD4;&#x8F83;&#x9EBB;&#x70E6;&#x7684;&#x89E3;&#x51B3;&#x65B9;&#x6848;&#xFF0C;&#x5C31;&#x662F;&#x518D;&#x6253;&#x5305;&#x4E00;&#x4E2A;&#x81EA;&#x7B7E;&#x540D;&#x7684;&#x8BC1;&#x4E66;&#x5230;&#x5B89;&#x88C5;&#x5305;&#xFF0C;&#x9501;&#x5B9A;&#x8FD9;&#x4E2A;&#x81EA;&#x7B7E;&#x540D;&#x7684;&#x8BC1;&#x4E66;&#x6765;&#x66F4;&#x65B0;&#x6700;&#x7EC8;&#x5B9E;&#x4F53;&#x8BC1;&#x4E66;&#xFF0C;&#x81EA;&#x7B7E;&#x540D;&#x8BC1;&#x4E66;&#x6709;&#x6548;&#x671F;&#x53EF;&#x4EE5;&#x81EA;&#x5B9A;&#x4E49;&#xFF0C;&#x5B9A;&#x7684;&#x8DB3;&#x591F;&#x957F;&#x5C31;&#x597D;&#xFF0C;&#x5F53;&#x7136;&#x670D;&#x52A1;&#x7AEF;&#x4E5F;&#x8BB8;&#x8981;&#x505A;&#x76F8;&#x5E94;&#x6539;&#x9020;&#xFF0C;&#x662F;&#x5426;&#x9700;&#x8981;&#x8FD9;&#x4E48;&#x4E25;&#x683C;&#x7684;&#x5B89;&#x5168;&#x7B56;&#x7565;&#x5C31;&#x770B;&#x4E1A;&#x52A1;&#x573A;&#x666F;&#x4E86;&#x3002;</p>
<h2 id="publickeypinning">Public Key Pinning</h2>
<p>Certificate Pinning&#x5B9E;&#x73B0;&#x8FC7;&#x4E8E;&#x7E41;&#x7410;&#xFF0C;&#x540C;&#x65F6;&#x5C40;&#x9650;&#x6027;&#x6BD4;&#x8F83;&#x5927;&#xFF0C;&#x6240;&#x4EE5;&#x5C31;&#x6709;&#x4E86;&#x9501;&#x5B9A;Subject Public Key Info&#x7684;&#x5B9E;&#x73B0;&#x3002;&#x7533;&#x8BF7;&#x8FC7;&#x8BC1;&#x4E66;&#x7684;&#x90FD;&#x77E5;&#x9053;&#xFF0C;&#x9700;&#x8981;&#x63D0;&#x4F9B;&#x7B97;&#x6CD5;&#x548C;&#x516C;&#x94A5;&#xFF0C;&#x5373;&#x4F7F;&#x66F4;&#x6362;&#x65B0;&#x8BC1;&#x4E66;&#xFF0C;&#x8FD9;&#x4E24;&#x4E2A;&#x4E1C;&#x897F;&#x4E5F;&#x662F;&#x53EF;&#x4EE5;&#x4FDD;&#x6301;&#x4E0D;&#x53D8;&#x7684;&#xFF0C;Android 7.0&#x4EE5;&#x4E0A;&#x63D0;&#x4F9B;&#x4E86;&#x975E;&#x5E38;&#x65B9;&#x4FBF;&#x7684;&#x5B9E;&#x73B0;&#xFF0C;&#x53EA;&#x9700;&#x8981;&#x5728;res/xml/network_security_config.xml&#x91CC;&#x52A0;&#x5982;&#x4E0B;&#x914D;&#x7F6E;&#xFF1A;</p>
<pre><code>&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
&lt;network-security-config&gt;
    &lt;domain-config&gt;
        &lt;domain includeSubdomains=&quot;true&quot;&gt;example.com&lt;/domain&gt;
        &lt;pin-set expiration=&quot;2018-01-01&quot;&gt;
            &lt;pin digest=&quot;SHA-256&quot;&gt;7HIpactkIAq2Y49orFOOQKurWxmmSFZhBCoQYcRhJ3Y=&lt;/pin&gt;
            &lt;!-- backup pin --&gt;
            &lt;pin digest=&quot;SHA-256&quot;&gt;fwza0LRMXouZHRC8Ei+4PyuldPDcf3UKgO/04cDM1oE=&lt;/pin&gt;
        &lt;/pin-set&gt;
    &lt;/domain-config&gt;
&lt;/network-security-config&gt;
</code></pre>
<p>&#x53EF;&#x4EE5;&#x53C2;&#x8003;Android&#x5B98;&#x65B9;&#x6587;&#x6863;&#xFF1A;<a href="https://developer.android.com/training/articles/security-config#CertificatePinning">https://developer.android.com/training/articles/security-config#CertificatePinning</a><br>
&#x8FD9;&#x91CC;pin&#x7684;&#x662F;Base64&#x7F16;&#x7801;&#x540E;&#x7684;Subject Public Key Info(SPKI)&#x7684;&#x54C8;&#x5E0C;&#xFF0C;&#x5177;&#x4F53;&#x751F;&#x6210;&#x65B9;&#x6CD5;&#x53EF;&#x4EE5;&#x53C2;&#x8003;Mozilla&#x7684;&#x6587;&#x6863;&#xFF1A;<a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Public_Key_Pinning#Extracting_the_Base64_encoded_public_key_information">https://developer.mozilla.org/en-US/docs/Web/HTTP/Public_Key_Pinning#Extracting_the_Base64_encoded_public_key_information</a></p>
<h3 id="fallback">fallback&#x7B56;&#x7565;</h3>
<p>&#x867D;&#x7136;&#x57FA;&#x4E8E;&#x516C;&#x94A5;&#x7684;&#x9501;&#x5B9A;&#x4E0D;&#x5B58;&#x5728;&#x8BC1;&#x4E66;&#x8FC7;&#x671F;&#x7684;&#x95EE;&#x9898;&#xFF0C;&#x4F46;&#x4F9D;&#x7136;&#x9700;&#x8981;fallback&#x7B56;&#x7565;&#xFF0C;&#x56E0;&#x4E3A;&#x53EF;&#x80FD;&#x5B58;&#x5728;&#x79C1;&#x94A5;&#x6CC4;&#x6F0F;&#x7684;&#x60C5;&#x51B5;&#x4E0B;&#xFF0C;&#x8FD9;&#x79CD;&#x60C5;&#x51B5;&#x4E0B;&#x9700;&#x8981;&#x91CD;&#x65B0;&#x53D1;&#x5E03;&#x8BC1;&#x4E66;&#xFF0C;&#x516C;&#x94A5;&#x79C1;&#x94A5;&#x90FD;&#x4F1A;&#x6539;&#x53D8;&#x3002;Android&#x5141;&#x8BB8;pin&#x591A;&#x4E2A;SPKI&#xFF0C;&#x53EA;&#x8981;&#x7B26;&#x5408;&#x4E00;&#x4E2A;&#x5C31;&#x80FD;&#x6B63;&#x5E38;&#x901A;&#x4FE1;&#xFF0C;&#x6240;&#x4EE5;&#x8FD9;&#x91CC;&#x53EF;&#x4EE5;pin&#x51E0;&#x4E2A;CA&#x7684;&#x6839;&#x8BC1;&#x4E66;&#x6216;&#x8005;&#x4E2D;&#x95F4;&#x8BC1;&#x4E66;&#x7684;SPKI&#xFF0C;&#x4F1A;&#x635F;&#x5931;&#x4E00;&#x70B9;&#x5B89;&#x5168;&#x6027;&#xFF0C;&#x4F46;&#x662F;&#x4E3A;&#x79C1;&#x94A5;&#x6CC4;&#x6F0F;&#x7684;&#x60C5;&#x51B5;&#x7559;&#x4E0B;&#x4E86;&#x64CD;&#x4F5C;&#x7A7A;&#x95F4;&#x3002;</p>
<h2 id>&#x7ED3;&#x8BED;</h2>
<p>&#x5373;&#x4F7F;&#x505A;&#x4E86;SSL Pinning&#xFF0C;&#x4F9D;&#x7136;&#x6709;HTTPS&#x88AB;&#x52AB;&#x6301;&#xFF0C;&#x5185;&#x5BB9;&#x88AB;&#x7BE1;&#x6539;&#x7684;&#x53EF;&#x80FD;&#xFF0C;&#x6BD4;&#x5982;&#x5BF9;&#x4E8E;&#x8BC1;&#x4E66;&#x9501;&#x5B9A;&#x7684;&#x65B9;&#x5F0F;&#xFF0C;&#x53EF;&#x4EE5;&#x76F4;&#x63A5;&#x66FF;&#x6362;&#x6389;apk&#x91CC;&#x7684;&#x8BC1;&#x4E66;&#xFF0C;&#x518D;&#x505A;&#x91CD;&#x6253;&#x5305;&#xFF0C;&#x5BF9;&#x4E8E;&#x516C;&#x94A5;&#x9501;&#x5B9A;&#x7684;&#x65B9;&#x5F0F;&#xFF0C;&#x53EF;&#x4EE5;&#x901A;&#x8FC7;hook RootTrustManager&#x7684;&#x65B9;&#x5F0F;&#x76F4;&#x63A5;&#x7ED5;&#x8FC7;&#x9A8C;&#x8BC1;&#x3002;<br>
&#x670D;&#x52A1;&#x7AEF;&#x9700;&#x8981;&#x5728;&#x4E1A;&#x52A1;&#x4E0A;&#x5BF9;&#x5BA2;&#x6237;&#x7AEF;&#x8BF7;&#x6C42;&#x505A;&#x9A8C;&#x8BC1;&#xFF0C;&#x53EA;&#x4F9D;&#x9760;&#x673A;&#x5236;&#x4E0A;&#x7684;&#x5B89;&#x5168;&#x662F;&#x4E0D;&#x591F;&#x7684;&#xFF0C;&#x9053;&#x9AD8;&#x4E00;&#x5C3A;&#x9B54;&#x9AD8;&#x4E00;&#x4E08;&#xFF0C;&#x5BA2;&#x6237;&#x7AEF;&#x548C;&#x670D;&#x52A1;&#x7AEF;&#x5E94;&#x8BE5;&#x4E92;&#x4E0D;&#x4FE1;&#x4EFB;&#xFF0C;&#x5BF9;&#x4E8E;&#x8F93;&#x5165;&#x9700;&#x8981;&#x505A;&#x8DB3;&#x591F;&#x7684;&#x6821;&#x9A8C;&#xFF0C;&#x8FD9;&#x5E76;&#x4E0D;&#x662F;&#x4E00;&#x79CD;overhead&#x3002;</p>
<!--kg-card-end: markdown--><p></p>]]></content:encoded></item><item><title><![CDATA[Telegram网络层源码分析]]></title><description><![CDATA[<!--kg-card-begin: markdown--><p>&#x6700;&#x8FD1;&#x770B;&#x4E86;&#x4E00;&#x4E0B;Telegram&#x7F51;&#x7EDC;&#x5C42;&#x7684;&#x6E90;&#x7801;&#xFF0C;&#x672C;&#x6765;&#x60F3;&#x7F51;&#x4E0A;&#x627E;&#x4E00;&#x4E0B;&#x73B0;&#x6210;&#x7684;&#x7ED3;&#x8BBA;&#xFF0C;&#x964D;&#x4F4E;&#x4E00;&#x70B9;&#x5B66;&#x4E60;&#x6210;&#x672C;&#xFF0C;&#x4F46;&#x662F;&#x5E76;&#x6CA1;&#x6709;&#x53D1;&#x73B0;&#x76F8;&#x5173;&#x7684;&#x8D44;&#x6599;&#x3002;</p>]]></description><link>https://shunix.com/telegram-connection/</link><guid isPermaLink="false">60812ae62b3f873b19511ec6</guid><category><![CDATA[技术文章]]></category><dc:creator><![CDATA[Shunix]]></dc:creator><pubDate>Wed, 02 May 2018 11:43:18 GMT</pubDate><content:encoded><![CDATA[<!--kg-card-begin: markdown--><p>&#x6700;&#x8FD1;&#x770B;&#x4E86;&#x4E00;&#x4E0B;Telegram&#x7F51;&#x7EDC;&#x5C42;&#x7684;&#x6E90;&#x7801;&#xFF0C;&#x672C;&#x6765;&#x60F3;&#x7F51;&#x4E0A;&#x627E;&#x4E00;&#x4E0B;&#x73B0;&#x6210;&#x7684;&#x7ED3;&#x8BBA;&#xFF0C;&#x964D;&#x4F4E;&#x4E00;&#x70B9;&#x5B66;&#x4E60;&#x6210;&#x672C;&#xFF0C;&#x4F46;&#x662F;&#x5E76;&#x6CA1;&#x6709;&#x53D1;&#x73B0;&#x76F8;&#x5173;&#x7684;&#x8D44;&#x6599;&#x3002;&#x4E8E;&#x662F;&#x81EA;&#x5DF1;&#x68B3;&#x7406;&#x4E86;&#x4E00;&#x4E0B;telegram&#x662F;&#x5982;&#x4F55;&#x53D1;&#x9001;&#x7F51;&#x7EDC;&#x8BF7;&#x6C42;&#x548C;&#x54CD;&#x5E94;&#x56DE;&#x5305;&#x7684;&#xFF0C;&#x8FD9;&#x91CC;&#x505A;&#x4E2A;&#x603B;&#x7ED3;&#x3002;</p>
<h4 id>&#x8FDE;&#x63A5;&#x7684;&#x5EFA;&#x7ACB;</h4>
<p>&#x5148;&#x4E0A;&#x4E00;&#x5F20;&#x56FE;&#xFF1A;<br>
<img src="https://raw.githubusercontent.com/shunix/BlogImages/master/200180428_connections_manager.png" alt="ConnectionsManager" loading="lazy"><br>
&#x8FD9;&#x5F20;&#x56FE;&#x63CF;&#x8FF0;&#x4E86;telegram&#x5BA2;&#x6237;&#x7AEF;&#x548C;server&#x7684;&#x8FDE;&#x63A5;&#x65F6;&#x5982;&#x4F55;&#x5EFA;&#x7ACB;&#x7684;&#x3002;Java&#x5C42;&#x7684;ConnectionsManager&#x662F;&#x4E00;&#x4E2A;&#x7EBF;&#x7A0B;&#x5B89;&#x5168;&#x7684;&#x5355;&#x4F8B;&#xFF0C;&#x5176;&#x5B9E;&#x53EA;&#x662F;&#x4E2A;wrapper&#xFF0C;&#x771F;&#x6B63;&#x7684;&#x903B;&#x8F91;&#x90FD;&#x662F;&#x8F6C;&#x4EA4;&#x7ED9;C++&#x5C42;&#x7684;ConnectionsManager&#x7C7B;&#x5904;&#x7406;&#x7684;&#x3002;  C++&#x5C42;&#x7684;ConnectionsManager&#x5BF9;&#x8C61;&#xFF0C;&#x5728;<em>TgNetWrapper.cpp</em>&#x4E2D;&#x521D;&#x59CB;&#x5316;&#xFF0C;&#x4E5F;&#x540C;&#x6837;&#x662F;&#x4E2A;&#x5355;&#x4F8B;&#x3002;&#x8FD9;&#x91CC;&#x8D34;&#x4E00;&#x4E0B;C++&#x5C42;ConnectionsManager&#x7C7B;&#x7684;init&#x65B9;&#x6CD5;:</p>
<script src="https://gist.github.com/shunix/1387303e7e90857a2c042b13bdb52d8a.js"></script>
<p>&#x8FD9;&#x91CC;&#x6709;&#x4E24;&#x4E2A;&#x5173;&#x952E;&#x7684;&#x65B9;&#x6CD5;&#x8C03;&#x7528;&#xFF0C;&#x4E00;&#x4E2A;&#x662F;loadConfig()&#xFF0C;&#x4E00;&#x4E2A;&#x662F;pthread_create()&#x3002;&#x987A;&#x7740;&#x65F6;&#x95F4;&#x7EBF;&#x5F80;&#x4E0B;&#x770B;&#xFF0C;loadConfig()&#x8C03;&#x7528;&#x4E86;initDataCenter()&#x65B9;&#x6CD5;&#xFF0C;&#x8FD9;&#x4E2A;&#x65B9;&#x6CD5;&#x5B9E;&#x73B0;&#x5982;&#x4E0B;:</p>
<script src="https://gist.github.com/shunix/0d635c4a089f25caf7cc950097280e33.js"></script>
<p>&#x53EF;&#x4EE5;&#x770B;&#x5230;&#xFF0C;&#x4E3B;&#x8981;&#x662F;&#x4E00;&#x4E9B;hardcode&#x7684;IP&#x548C;&#x7AEF;&#x53E3;&#xFF0C;&#x5176;&#x5B9E;&#x5728;&#x8FDE;&#x63A5;&#x4E0A;&#x7B2C;&#x4E00;&#x4E2A;&#x6570;&#x636E;&#x4E2D;&#x5FC3;&#x4E4B;&#x540E;&#xFF0C;&#x5BA2;&#x6237;&#x7AEF;&#x5C31;&#x4F1A;&#x88AB;&#x5206;&#x53D1;&#x5230;&#x6700;&#x4F18;&#x7684;&#x6570;&#x636E;&#x4E2D;&#x5FC3;&#x63A5;&#x5165;&#xFF0C;&#x8FD9;&#x91CC;&#x5199;&#x8FD9;&#x4E48;&#x591A;&#xFF0C;&#x53EF;&#x4EE5;&#x770B;&#x4F5C;&#x4E00;&#x79CD;fallback&#x903B;&#x8F91;&#x3002;<br>
&#x63A5;&#x4E0B;&#x6765;&#x4F7F;&#x7528;&#x4E86;&#x4E00;&#x4E2A;pthread_create&#x7684;&#x8C03;&#x7528;&#xFF0C;&#x65B0;&#x7684;&#x7EBF;&#x7A0B;&#x4E2D;&#x4F1A;&#x6267;&#x884C;ThreadProc()&#x65B9;&#x6CD5;&#xFF0C;&#x8FD9;&#x4E2A;&#x65B9;&#x6CD5;&#x4F1A;&#x5148;&#x8C03;&#x7528;sendPing()&#xFF0C;&#x5B9E;&#x73B0;&#x5982;&#x4E0B;&#xFF1A;</p>
<script src="https://gist.github.com/shunix/9564015b78e9db2134eeebbaecd804f9.js"></script>
<p>&#x8FD9;&#x91CC;&#x8C03;&#x7528;&#x4E86;DataCenter&#x7684;getPushConnection()&#x548C;getGenericConnection()&#x65B9;&#x6CD5;&#xFF0C;&#x8FD9;&#x91CC;&#x628A;connection&#x7C7B;&#x578B;&#x533A;&#x5206;&#x5F00;&#x7684;&#x672C;&#x610F;&#x662F;&#x4E0B;&#x8F7D;&#xFF0C;&#x63A8;&#x9001;&#x7B49;&#x4F7F;&#x7528;&#x4E0D;&#x540C;&#x7684;&#x8FDE;&#x63A5;&#xFF0C;&#x8FD9;&#x6837;&#x53EF;&#x4EE5;&#x9632;&#x6B62;&#x4E00;&#x4E9B;&#x8017;&#x65F6;&#x4EFB;&#x52A1;&#x4E00;&#x76F4;&#x5360;&#x7528;&#x8FDE;&#x63A5;&#xFF0C;&#x540C;&#x4E00;&#x4E2A;&#x6570;&#x636E;&#x4E2D;&#x5FC3;&#xFF0C;&#x53EF;&#x4EE5;&#x7ED9;&#x4E0D;&#x540C;&#x7C7B;&#x578B;&#x7684;&#x8FDE;&#x63A5;&#x5206;&#x914D;&#x4E0D;&#x540C;&#x7684;IP&#x548C;&#x7AEF;&#x53E3;&#xFF0C;&#x6765;&#x63D0;&#x9AD8;&#x7F51;&#x7EDC;&#x8FDE;&#x63A5;&#x7684;&#x6548;&#x7387;&#x3002;<br>
&#x63A5;&#x4E0B;&#x6765;&#x662F;&#x4E00;&#x4E2A;&#x5FAA;&#x73AF;&#xFF0C;&#x5FAA;&#x73AF;&#x4E2D;&#x4E0D;&#x65AD;&#x8C03;&#x7528;select()&#x65B9;&#x6CD5;&#xFF0C;&#x6765;&#x5904;&#x7406;&#x8BF7;&#x6C42;&#xFF0C;&#x8FD9;&#x4E2A;&#x65B9;&#x6CD5;&#x7684;&#x5B9E;&#x73B0;&#x5982;&#x4E0B;&#xFF1A;</p>
<script src="https://gist.github.com/shunix/6aaca8d2a25fe1c08616ba780904dbea.js"></script>
<p>&#x8FD9;&#x91CC;&#x6709;&#x4E00;&#x4E2A;epoll_wait()&#x7684;&#x8C03;&#x7528;&#xFF0C;&#x76F4;&#x89C9;&#x4E0A;&#x6765;&#x8BF4;&#xFF0C;&#x8FD9;&#x5C31;&#x662F;&#x5904;&#x7406;&#x7F51;&#x7EDC;&#x8BF7;&#x6C42;&#x7684;&#x6838;&#x5FC3;&#xFF0C;&#x6240;&#x4EE5;&#x6211;&#x4EEC;&#x4E5F;&#x4ECE;&#x8FD9;&#x91CC;&#x5F00;&#x59CB;&#x5206;&#x6790;&#xFF0C;&#x5148;&#x770B;&#x4E00;&#x4E0B;&#x8FD9;&#x4E2A;<strong>epolFd</strong>&#x4E0A;&#x6CE8;&#x518C;&#x7684;fd:</p>
<script src="https://gist.github.com/shunix/9c4af3ce3d99dffe6da293bfbc35d428.js"></script>
<p>&#x8FD9;&#x91CC;&#x5206;&#x6790;&#x4E00;&#x4E0B;&#xFF0C;<strong>epolFd</strong>&#x4E0A;&#x6CE8;&#x518C;&#x7684;fd&#x4E00;&#x5171;&#x6709;&#x4E24;&#x7C7B;&#xFF1A;</p>
<ol>
<li>socket&#x3002;&#x8FD9;&#x91CC;&#x53EF;&#x4EE5;&#x770B;&#x5230;&#xFF0C;socket&#x8FDE;&#x63A5;&#x5728;&#x521B;&#x5EFA;&#x65F6;&#xFF0C;&#x4F1A;&#x5411;epoll&#x6CE8;&#x518C;&#x81EA;&#x5DF1;&#xFF0C;&#x5728;&#x5173;&#x95ED;&#x65F6;&#x4F1A;&#x628A;&#x81EA;&#x5DF1;&#x4ECE;epoll&#x7684;&#x76D1;&#x89C6;&#x5217;&#x8868;&#x79FB;&#x9664;&#x3002;&#x800C;adjustWriteOp()&#x65B9;&#x6CD5;&#x662F;&#x5728;socket&#x53D1;&#x9001;&#x6570;&#x636E;&#x65F6;&#x8C03;&#x7528;&#xFF0C;&#x6211;&#x4EEC;&#x77E5;&#x9053;&#xFF0C;&#x5BF9;&#x4E8E;socket&#x7684;send&#xFF0C;&#x53EA;&#x662F;&#x628A;&#x6570;&#x636E;&#x53D1;&#x9001;&#x5230;&#x4E86;&#x7F13;&#x51B2;&#x533A;&#xFF0C;&#x5982;&#x679C;&#x7F13;&#x51B2;&#x533A;&#x6EE1;&#x4F1A;&#x89E6;&#x53D1;<strong>EAGAIN</strong>&#xFF0C;&#x8FD9;&#x4E2A;&#x65F6;&#x5019;&#x5C31;&#x8981;&#x76D1;&#x542C;<strong>EPOLLOUT</strong>&#xFF0C;&#x8868;&#x793A;&#x7F13;&#x51B2;&#x533A;&#x53EF;&#x5199;&#xFF0C;adjustWriteOp()&#x65B9;&#x6CD5;&#x5B8C;&#x6210;&#x7684;&#x5C31;&#x662F;&#x8FD9;&#x4E2A;&#x64CD;&#x4F5C;&#x3002;</li>
<li>&#x7528;&#x4E8E;&#x4E8B;&#x4EF6;&#x901A;&#x77E5;&#x7684;fd&#xFF0C;&#x8FD9;&#x91CC;&#x6709;<strong>eventFd</strong>&#x548C;<strong>pipeFd</strong>&#x3002;&#x8FD9;&#x4E24;&#x4E2A;&#x7528;&#x4E8E;&#x4E8B;&#x4EF6;&#x901A;&#x77E5;&#x7684;fd&#x4E0D;&#x4F1A;&#x540C;&#x65F6;&#x4F7F;&#x7528;&#xFF0C;&#x5148;&#x521D;&#x59CB;&#x5316;eventFd&#xFF0C;pipeFd&#x4EC5;&#x4EC5;&#x662F;&#x5728;eventFd&#x65E0;&#x6CD5;&#x6210;&#x529F;&#x521D;&#x59CB;&#x5316;&#x65F6;&#x7684;&#x5907;&#x9009;&#x65B9;&#x6848;&#x3002;&#x8FD9;&#x4E24;&#x4E2A;fd&#x5177;&#x4F53;&#x7528;&#x5728;&#x54EA;&#x91CC;&#x53EF;&#x4EE5;&#x770B;&#x4E0B;&#x9762;&#x7684;&#x4EE3;&#x7801;&#x6BB5;&#x3002;</li>
</ol>
<script src="https://gist.github.com/shunix/19e18b3b304743bfdb61a871ce350486.js"></script>
<p>wakeup()&#x65B9;&#x6CD5;&#x8C03;&#x7528;&#x7684;&#x5730;&#x65B9;&#x5728;&#x8FD9;&#x91CC;&#xFF1A;</p>
<script src="https://gist.github.com/shunix/4c8ccd5352290aee9cb7b2ed2759049d.js"></script>
<p>&#x8FD9;&#x4E2A;scheduleTask()&#x65B9;&#x6CD5;&#x662F;&#x5199;&#x5F97;&#x6700;&#x8010;&#x4EBA;&#x5BFB;&#x5473;&#x7684;&#x5730;&#x65B9;&#x3002;&#x6211;&#x672C;&#x6765;&#x4EE5;&#x4E3A;&#xFF0C;&#x8FD9;&#x53EA;&#x662F;&#x4E2A;&#x7F51;&#x7EDC;&#x8BF7;&#x6C42;&#x7684;&#x4EFB;&#x52A1;&#x961F;&#x5217;&#xFF0C;&#x540E;&#x6765;&#x67E5;&#x4E86;&#x4E00;&#x4E0B;&#x8FD9;&#x4E2A;&#x65B9;&#x6CD5;&#x7684;&#x8C03;&#x7528;&#xFF0C;&#x53D1;&#x73B0;&#x8FD9;&#x4E2A;&#x961F;&#x5217;&#x7684;&#x4E1C;&#x897F;&#x771F;&#x662F;&#x5305;&#x7F57;&#x4E07;&#x8C61;&#xFF0C;&#x4EC0;&#x4E48;&#x52A0;&#x8F7D;&#x6587;&#x4EF6;&#xFF0C;&#x52A0;&#x8F7D;&#x914D;&#x7F6E;&#xFF0C;&#x8BBE;&#x7F6E;dns&#xFF0C;&#x8BBE;&#x7F6E;&#x8BED;&#x8A00;&#x7B49;&#x4EFB;&#x52A1;&#x90FD;&#x653E;&#x5230;&#x4E86;&#x8FD9;&#x4E2A;&#x961F;&#x5217;&#x91CC;&#xFF0C;&#x611F;&#x89C9;&#x4E0A;&#x662F;&#x4E00;&#x4E2A;jni&#x5C42;&#x5168;&#x5C40;&#x7684;&#x8C03;&#x5EA6;&#x5668;&#x3002;&#x800C;&#x5BF9;&#x4E8E;&#x7F51;&#x7EDC;&#x8BF7;&#x6C42;&#xFF0C;&#x90FD;&#x662F;&#x653E;&#x5728;<strong>requestQueue</strong>&#x4E2D;&#xFF0C;&#x67E5;&#x770B;sendRequest()&#x65B9;&#x6CD5;&#x4E0D;&#x96BE;&#x770B;&#x51FA;&#x6765;&#xFF0C;&#x5904;&#x7406;&#x7F51;&#x7EDC;&#x8BF7;&#x6C42;&#x662F;&#x5728;processRequestQueue()&#x65B9;&#x6CD5;&#x4E2D;&#x8FDB;&#x884C;&#x7684;&#x3002;<br>
&#x73B0;&#x5728;&#x518D;&#x6765;&#x770B;select()&#x65B9;&#x6CD5;&#xFF0C;&#x6D41;&#x7A0B;&#x5C31;&#x6E05;&#x695A;&#x591A;&#x4E86;&#xFF0C;epoll_wait&#x4F1A;&#x5728;&#x4EE5;&#x4E0B;&#x51E0;&#x79CD;&#x60C5;&#x51B5;&#x4E0B;&#x88AB;&#x5524;&#x9192;&#xFF1A;</p>
<ol>
<li>socket&#x8FDE;&#x63A5;&#x6709;&#x6570;&#x636E;&#x9700;&#x8981;&#x63A5;&#x6536;</li>
<li>socket&#x7F13;&#x51B2;&#x533A;&#x53EF;&#x5199;&#xFF0C;&#x4E0A;&#x4E00;&#x6B21;&#x53D1;&#x9001;&#x7684;&#x6570;&#x636E;&#x6CA1;&#x6709;&#x5B8C;&#x6210;</li>
<li>&#x6709;&#x4EFB;&#x52A1;&#x5728;<strong>pendingTasks</strong>&#x961F;&#x5217;&#x4E2D;</li>
</ol>
<p>&#x5F53;&#x7EBF;&#x7A0B;&#x88AB;&#x5524;&#x9192;&#xFF0C;&#x4E0D;&#x518D;&#x963B;&#x585E;&#x4E4B;&#x540E;&#xFF0C;&#x4F1A;&#x9996;&#x5148;&#x53BB;&#x5904;&#x7406;pendingTasks&#x961F;&#x5217;&#x4E2D;&#x7684;&#x8BF7;&#x6C42;&#x3002;&#x7136;&#x540E;&#x8C03;&#x7528;epoll&#x8FD4;&#x56DE;&#x7684;EventObject&#x5BF9;&#x8C61;&#x7684;onEvent()&#x65B9;&#x6CD5;&#x4F9D;&#x6B21;&#x5904;&#x7406;&#xFF0C;&#x8FD9;&#x4E2A;EventObject&#x65B9;&#x6CD5;&#x5176;&#x5B9E;&#x53EF;&#x4EE5;&#x770B;&#x4F5C;&#x4E00;&#x4E2A;wrapper&#xFF0C;&#x4F1A;&#x6839;&#x636E;EventObjectType&#x628A;&#x903B;&#x8F91;&#x5206;&#x53D1;&#x5230;&#x5404;&#x4E2A;&#x5BF9;&#x8C61;&#x4E0A;&#xFF0C;&#x4EE3;&#x7801;&#x5982;&#x4E0B;&#xFF1A;</p>
<script src="https://gist.github.com/shunix/ba262d1aead4c4b5e52aaf56502fc57f.js"></script>
<p>&#x5BF9;&#x4E8E;epoll&#xFF0C;&#x4F1A;&#x7528;&#x5230;&#x7684;&#x7C7B;&#x578B;&#x662F;EventObjectTypeConnection, EventObjectTypePipe, EventObjectTypeEvent.<br>
&#x5B8C;&#x6210;EventObject&#x7684;&#x5904;&#x7406;&#x4E4B;&#x540E;&#xFF0C;&#x63A5;&#x4E0B;&#x6765;&#x4F1A;&#x5173;&#x95ED;&#x8D85;&#x65F6;&#x8FDE;&#x63A5;&#xFF0C;&#x8FD9;&#x91CC;&#x7684;&#x8D85;&#x65F6;&#x65F6;&#x95F4;&#x662F;12&#x79D2;&#xFF0C;&#x7136;&#x540E;&#x8981;&#x5904;&#x7406;&#x957F;&#x8FDE;&#x63A5;&#x7684;&#x5FC3;&#x8DF3;&#x3002;&#x8FD9;&#x91CC;&#x5BF9;&#x4E8E;&#x957F;&#x8FDE;&#x63A5;&#x5FC3;&#x8DF3;&#x7684;&#x5904;&#x7406;&#x5982;&#x4E0B;&#xFF1A;</p>
<ol>
<li>&#x5173;&#x95ED;&#x8D85;&#x65F6;&#x7684;&#x957F;&#x8FDE;&#x63A5;&#x3002;&#x8FD9;&#x91CC;&#x5BF9;&#x4E8E;&#x8D85;&#x65F6;&#x7684;&#x5224;&#x5B9A;&#x6709;&#x4E24;&#x4E2A;&#x6761;&#x4EF6;&#xFF0C;&#x4E00;&#x662F;&#x53D1;&#x9001;&#x5FC3;&#x8DF3;&#x5305;&#x6CA1;&#x6709;&#x6536;&#x5230;&#x56DE;&#x5305;&#xFF0C;&#x5DF2;&#x7ECF;&#x8FC7;&#x53BB;&#x4E86;30s&#xFF0C;&#x4E8C;&#x662F;&#x8DDD;&#x79BB;&#x4E0A;&#x6B21;&#x53D1;&#x9001;&#x5FC3;&#x8DF3;&#x5305;&#x65F6;&#x95F4;&#x5DF2;&#x7ECF;&#x8FC7;&#x4E86;190s&#x3002;</li>
<li>&#x5224;&#x65AD;&#x5F53;&#x524D;&#x65F6;&#x95F4;&#x8DDD;&#x79BB;&#x4E0A;&#x4E00;&#x6B21;&#x53D1;&#x9001;&#x5FC3;&#x8DF3;&#x5305;&#x662F;&#x5426;&#x5DF2;&#x7ECF;&#x8D85;&#x8FC7;&#x4E86;180s&#xFF0C;&#x5982;&#x679C;&#x662F;&#x7684;&#x8BDD;&#xFF0C;&#x5219;&#x53D1;&#x9001;&#x957F;&#x8FDE;&#x63A5;&#x5FC3;&#x8DF3;&#x5305;&#x3002;&#x8FD9;&#x91CC;&#x53EF;&#x4EE5;&#x5F97;&#x51FA;&#x7ED3;&#x8BBA;&#xFF0C;<strong>Telegram&#x7684;&#x957F;&#x8FDE;&#x63A5;&#x5FC3;&#x8DF3;&#x5468;&#x671F;&#x662F;3&#x5206;&#x949F;</strong>&#x3002;<br>
&#x63A5;&#x4E0B;&#x7684;&#x5904;&#x7406;&#x975E;&#x5E38;&#x826F;&#x5FC3;&#xFF0C;Telegram&#x5728;&#x68C0;&#x6D4B;&#x5230;&#x5F53;&#x524D;&#x961F;&#x5217;&#x6CA1;&#x6709;&#x4E0A;&#x4F20;&#x4E0B;&#x8F7D;&#x4EFB;&#x52A1;&#x548C;&#x5411;server&#x8BF7;&#x6C42;&#x76D0;&#x503C;&#x7684;&#x4EFB;&#x52A1;&#x65F6;&#xFF0C;&#x4F1A;&#x5173;&#x95ED;&#x548C;&#x6570;&#x636E;&#x4E2D;&#x5FC3;&#x7684;socket&#x8FDE;&#x63A5;&#x3002;&#x8FD9;&#x91CC;&#x6709;&#x4E00;&#x4E2A;&#x9608;&#x503C;&#x662F;10s&#xFF0C;&#x53EF;&#x4EE5;&#x8BA4;&#x4E3A;&#xFF0C;&#x5982;&#x679C;&#x628A;&#x5E94;&#x7528;&#x5207;&#x5230;&#x540E;&#x53F0;&#xFF0C;&#x5728;&#x5B8C;&#x6210;&#x5F53;&#x524D;&#x961F;&#x5217;&#x91CC;&#x7684;&#x4E0A;&#x4F20;&#x548C;&#x4E0B;&#x8F7D;&#x8BF7;&#x6C42;10s&#x540E;&#xFF0C;Telegram&#x5C31;&#x4F1A;&#x5173;&#x95ED;&#x957F;&#x8FDE;&#x63A5;&#xFF0C;&#x505C;&#x6B62;&#x53D1;&#x5FC3;&#x8DF3;&#x3002;&#x8FD9;&#x4E2A;&#x64CD;&#x4F5C;&#x975E;&#x5E38;&#x7701;&#x7535;&#xFF0C;&#x53CD;&#x89C2;&#x56FD;&#x5185;&#x5927;&#x628A;app&#xFF0C;&#x5404;&#x79CD;&#x9ED1;&#x79D1;&#x6280;&#x4FDD;&#x6D3B;&#x3002;<br>
&#x90A3;&#x4E48;&#x6709;&#x4E00;&#x4E2A;&#x95EE;&#x9898;&#xFF0C;Telegram&#x662F;&#x5982;&#x4F55;&#x4FDD;&#x8BC1;&#x4F11;&#x7720;&#x540E;&#x8FD8;&#x80FD;&#x63A5;&#x6536;&#x5230;&#x6D88;&#x606F;&#x5462;&#xFF1F;&#x7B54;&#x6848;&#x662F;GCM&#xFF0C;&#x4ECE;AndroidManifest.xml&#x91CC;&#x5F88;&#x5BB9;&#x6613;&#x627E;&#x5230;GCM&#x5BF9;&#x5E94;service&#x7684;&#x5B9E;&#x73B0;&#x7C7B;&#xFF1A;</li>
</ol>
<script src="https://gist.github.com/shunix/db722d2604dfdc79da74fd4292c8c88c.js"></script>
<p>&#x8FD9;&#x91CC;&#x7684;ConnectionsManager.getInstance().resumeNetworkMaybe()&#x5C31;&#x662F;&#x5C1D;&#x8BD5;&#x91CD;&#x65B0;&#x6062;&#x590D;&#x957F;&#x8FDE;&#x63A5;&#x7684;&#x64CD;&#x4F5C;&#xFF0C;&#x903B;&#x8F91;&#x5F88;&#x7B80;&#x5355;&#xFF0C;&#x5C31;&#x4E0D;&#x518D;&#x8D58;&#x8FF0;&#x3002;<br>
&#x6700;&#x540E;&#x4E00;&#x6B65;&#xFF0C;&#x5BF9;&#x4E8E;&#x548C;DataCenter&#x7684;&#x666E;&#x901A;&#x8FDE;&#x63A5;&#xFF0C;&#x4E5F;&#x53D1;&#x9001;&#x5FC3;&#x8DF3;&#x4FDD;&#x6D3B;&#xFF0C;&#x8FD9;&#x91CC;&#x7684;&#x5FC3;&#x8DF3;&#x5468;&#x671F;&#x662F;19s&#xFF0C;&#x7136;&#x540E;&#x6BCF;&#x5C0F;&#x65F6;&#x66F4;&#x65B0;&#x4E00;&#x6B21;DataCenter&#x7684;&#x914D;&#x7F6E;&#x3002;&#x518D;&#x8C03;&#x7528;processRequestQueue()&#x65B9;&#x6CD5;&#x5F00;&#x59CB;&#x5904;&#x7406;&#x8BF7;&#x6C42;&#x961F;&#x5217;&#x4E2D;&#x7684;&#x4EFB;&#x52A1;&#x3002;<br>
&#x8FD9;&#x91CC;&#x6574;&#x7406;&#x4E86;&#x4E00;&#x4E2A;&#x6BD4;&#x8F83;&#x76F4;&#x89C2;&#x7684;&#x6D41;&#x7A0B;&#x56FE;&#xFF0C;&#x8BF4;&#x660E;&#x4E86;&#x53D1;&#x8D77;&#x8BF7;&#x6C42;&#x7684;&#x8FC7;&#x7A0B;&#x3002;<br>
<img src="https://raw.githubusercontent.com/shunix/BlogImages/master/20180502_connections_manager_select.png" alt="select" loading="lazy"></p>
<p>Telegram&#x7F51;&#x7EDC;&#x6A21;&#x5757;&#x7684;&#x5206;&#x6790;&#x5C31;&#x5230;&#x8FD9;&#x91CC;&#x4E86;&#x3002;</p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[Android N多窗口适配]]></title><description><![CDATA[<!--kg-card-begin: markdown--><h4 id>&#x524D;&#x8A00;</h4>
<p>&#x4ECE;Android 7.0&#x5F00;&#x59CB;&#xFF0C;&#x7CFB;&#x7EDF;&#x5C31;&#x5F00;&#x59CB;&#x652F;&#x6301;&#x591A;&#x7A97;&#x53E3;&#x6A21;&#x5F0F;&#xFF0C;&#x5BF9;&#x4E8E;&#x591A;&#x7A97;&#x53E3;&#x6A21;&#x5F0F;&#x7684;&#x9002;&#x914D;&#xFF0C;&#x4E3B;&#x8981;&#x662F;&#x4E24;&#x65B9;&#x9762;&#xFF0C;UI&#x9002;&#x914D;&#x548C;&#x751F;&#x547D;&#x5468;&#x671F;&#x7684;&#x8C03;</p>]]></description><link>https://shunix.com/multi-window-support/</link><guid isPermaLink="false">60812ae62b3f873b19511ec5</guid><category><![CDATA[技术文章]]></category><dc:creator><![CDATA[Shunix]]></dc:creator><pubDate>Mon, 09 Apr 2018 10:32:39 GMT</pubDate><content:encoded><![CDATA[<!--kg-card-begin: markdown--><h4 id>&#x524D;&#x8A00;</h4>
<p>&#x4ECE;Android 7.0&#x5F00;&#x59CB;&#xFF0C;&#x7CFB;&#x7EDF;&#x5C31;&#x5F00;&#x59CB;&#x652F;&#x6301;&#x591A;&#x7A97;&#x53E3;&#x6A21;&#x5F0F;&#xFF0C;&#x5BF9;&#x4E8E;&#x591A;&#x7A97;&#x53E3;&#x6A21;&#x5F0F;&#x7684;&#x9002;&#x914D;&#xFF0C;&#x4E3B;&#x8981;&#x662F;&#x4E24;&#x65B9;&#x9762;&#xFF0C;UI&#x9002;&#x914D;&#x548C;&#x751F;&#x547D;&#x5468;&#x671F;&#x7684;&#x8C03;&#x6574;&#xFF0C;&#x9002;&#x914D;&#x7684;&#x5DE5;&#x4F5C;&#x91CF;&#x56E0;App&#x800C;&#x5F02;&#xFF0C;&#x4E0B;&#x9762;&#x5C31;&#x4ECE;&#x51E0;&#x4E2A;&#x65B9;&#x9762;&#x6765;&#x8C08;&#x8C08;&#x591A;&#x7A97;&#x53E3;&#x6A21;&#x5F0F;&#x7684;&#x9002;&#x914D;&#x3002;</p>
<h4 id>&#x591A;&#x7A97;&#x53E3;&#x6A21;&#x5F0F;&#x89C4;&#x5219;</h4>
<p>&#x8FD9;&#x91CC;&#x8981;&#x6CE8;&#x610F;&#xFF0C;&#x591A;&#x7A97;&#x53E3;&#x6A21;&#x5F0F;&#x5206;&#x4E3A;&#x4E24;&#x79CD;&#xFF0C;split-screen&#x6A21;&#x5F0F;&#x548C;freeform&#x6A21;&#x5F0F;&#xFF0C;&#x524D;&#x8005;&#x662F;&#x5355;&#x7EAF;&#x7684;&#x5C4F;&#x5E55;&#x4E00;&#x5206;&#x4E3A;&#x4E8C;&#xFF0C;&#x800C;&#x540E;&#x8005;&#x5141;&#x8BB8;&#x7528;&#x6237;&#x81EA;&#x7531;&#x8C03;&#x6574;&#x4E24;&#x4E2A;activity&#x7684;&#x5927;&#x5C0F;&#x3002;&#x6839;&#x636E;&#x5B98;&#x65B9;&#x6587;&#x6863;&#x7684;&#x8BF4;&#x6CD5;&#xFF0C;&#x6240;&#x6709;Android N&#x7684;&#x8BBE;&#x5907;&#x90FD;&#x662F;&#x652F;&#x6301;split-screen&#x6A21;&#x5F0F;&#x7684;&#xFF0C;&#x800C;freeform&#x6A21;&#x5F0F;&#x7531;&#x5382;&#x5546;&#x51B3;&#x5B9A;&#x662F;&#x5426;&#x5F00;&#x542F;&#xFF0C;&#x4E00;&#x822C;&#x5C4F;&#x5E55;&#x6BD4;&#x8F83;&#x5927;&#x7684;&#x8BBE;&#x5907;&#x90FD;&#x652F;&#x6301;&#x8FD9;&#x4E2A;&#x6A21;&#x5F0F;&#x3002;<br>
AndroidManifest.xml&#x4E2D;&#x7684;<code>android:resizeableActivity</code>&#x5C5E;&#x6027;&#x548C;&#x5E94;&#x7528;&#x7684;targetSDK&#x5171;&#x540C;&#x5F71;&#x54CD;&#x7740;&#x5E94;&#x7528;&#x5728;&#x5206;&#x5C4F;&#x6A21;&#x5F0F;&#x4E0B;&#x7684;&#x884C;&#x4E3A;&#xFF0C;&#x8FD9;&#x91CC;&#x5148;&#x8BA8;&#x8BBA;&#x5E94;&#x7528;&#x6CA1;&#x6709;&#x6307;&#x5B9A;orientation&#x7684;&#x60C5;&#x51B5;&#x3002;&#x5982;&#x679C;&#x5E94;&#x7528;&#x7684;targetSDK&#x662F;24&#x53CA;&#x4EE5;&#x4E0A;&#xFF0C;&#x90A3;&#x4E48;android:resizeableActivity&#x5C5E;&#x6027;&#x9ED8;&#x8BA4;&#x4E3A;true&#xFF0C;&#x5E94;&#x7528;&#x9ED8;&#x8BA4;&#x652F;&#x6301;&#x591A;&#x7A97;&#x53E3;&#x6A21;&#x5F0F;&#xFF0C;&#x5F53;&#x7136;&#x5E94;&#x7528;&#x53EF;&#x4EE5;&#x624B;&#x52A8;&#x8986;&#x76D6;&#x6389;&#x8FD9;&#x4E2A;&#x9ED8;&#x8BA4;&#x503C;&#x3002;&#x5982;&#x679C;&#x5E94;&#x7528;&#x7684;targetSDK&#x662F;23&#x53CA;&#x5176;&#x4EE5;&#x4E0B;&#xFF0C;&#x90A3;&#x4E48;&#x8981;&#x5206;&#x4E3A;&#x4E09;&#x79CD;&#x60C5;&#x51B5;&#x3002;&#x4E00;&#x662F;&#x8FD9;&#x4E2A;&#x5C5E;&#x6027;&#x6CA1;&#x6709;&#x88AB;&#x6307;&#x5B9A;&#xFF0C;&#x90A3;&#x4E48;&#x5728;&#x8FDB;&#x5165;&#x591A;&#x7A97;&#x53E3;&#x6A21;&#x5F0F;&#x65F6;&#xFF0C;&#x7CFB;&#x7EDF;&#x4F1A;&#x5F3A;&#x5236;&#x7F29;&#x653E;&#x5E94;&#x7528;&#xFF0C;&#x5E76;&#x4E14;&#x5F39;&#x51FA;&#x4E00;&#x4E2A;&#x63D0;&#x793A;&#x6846;&#xFF0C;&#x544A;&#x8BC9;&#x7528;&#x6237;&#x5F53;&#x524D;&#x5E94;&#x7528;&#x5728;&#x591A;&#x7A97;&#x53E3;&#x6A21;&#x5F0F;&#x4E0B;&#x53EF;&#x80FD;&#x8868;&#x73B0;&#x5F02;&#x5E38;&#xFF1B;&#x4E8C;&#x662F;&#x8FD9;&#x4E2A;&#x5C5E;&#x6027;&#x4E3A;false&#xFF0C;&#x90A3;&#x4E48;&#x8FD9;&#x4E2A;&#x5E94;&#x7528;&#x65E0;&#x6CD5;&#x8FDB;&#x5165;&#x591A;&#x7A97;&#x53E3;&#x6A21;&#x5F0F;&#xFF0C;&#x4E00;&#x5B9A;&#x662F;&#x4EE5;&#x5168;&#x5C4F;&#x72B6;&#x6001;&#x542F;&#x52A8;&#x7684;&#xFF1B;&#x4E09;&#x662F;&#x8FD9;&#x4E2A;&#x5C5E;&#x6027;&#x88AB;&#x624B;&#x52A8;&#x6307;&#x5B9A;&#x4E3A;true&#xFF0C;&#x90A3;&#x4E48;&#x5E94;&#x7528;&#x5C06;&#x6B63;&#x5E38;&#x8FDB;&#x5165;&#x591A;&#x7A97;&#x53E3;&#x6A21;&#x5F0F;&#xFF0C;&#x5E76;&#x4E14;&#x4E0D;&#x4F1A;&#x6709;&#x60C5;&#x51B5;&#x4E00;&#x4E2D;&#x7684;&#x63D0;&#x793A;&#x6846;&#x3002;<br>
&#x5982;&#x679C;&#x4E00;&#x4E2A;task&#x6808;&#x4E2D;&#x7684;&#x6839;activity&#x652F;&#x6301;&#x591A;&#x7A97;&#x53E3;&#x6A21;&#x5F0F;&#xFF0C;&#x90A3;&#x4E48;&#x8FD9;&#x4E2A;&#x6808;&#x4E2D;&#x7684;&#x6240;&#x6709;activity&#x90FD;&#x652F;&#x6301;&#x591A;&#x7A97;&#x53E3;&#x6A21;&#x5F0F;&#x3002;&#x8FD9;&#x6761;&#x89C4;&#x5219;&#x5C31;&#x610F;&#x5473;&#x7740;&#xFF0C;&#x5982;&#x679C;&#x6211;&#x4EEC;&#x7684;&#x5E94;&#x7528;launcher activity&#x652F;&#x6301;&#x591A;&#x7A97;&#x53E3;&#x6A21;&#x5F0F;&#xFF0C;&#x90A3;&#x4E48;&#x6240;&#x6709;&#x53EF;&#x80FD;&#x7531;&#x5185;&#x90E8;&#x8C03;&#x7528;&#x547C;&#x8D77;&#x7684;activity&#x4E5F;&#x5FC5;&#x987B;&#x9002;&#x914D;&#x591A;&#x7A97;&#x53E3;&#x6A21;&#x5F0F;&#x3002;</p>
<h4 id="orientation">orientation&#x7684;&#x5F71;&#x54CD;</h4>
<p>&#x4E0A;&#x4E00;&#x8282;&#x53EA;&#x8BA8;&#x8BBA;&#x4E86;&#x6CA1;&#x6709;activity&#x6CA1;&#x6709;&#x6307;&#x5B9A;orientation&#x7684;&#x60C5;&#x51B5;&#xFF0C;&#x5176;&#x5B9E;orientation&#x76F8;&#x5173;&#x7684;&#x5C5E;&#x6027;&#xFF0C;&#x5BF9;&#x5E94;&#x7528;&#x5728;&#x591A;&#x7A97;&#x53E3;&#x6A21;&#x5F0F;&#x4E0B;&#x7684;&#x8868;&#x73B0;&#x4E5F;&#x6709;&#x5F88;&#x5927;&#x7684;&#x5F71;&#x54CD;&#x3002;&#x5F88;&#x591A;&#x9875;&#x9762;&#x4F1A;&#x6307;&#x5B9A;<code>android:screenOrientation</code>&#x5C5E;&#x6027;&#x6765;&#x9501;&#x5B9A;&#x5C4F;&#x5E55;&#x65B9;&#x5411;&#xFF0C;&#x8FD9;&#x4E2A;&#x5C5E;&#x6027;&#x6839;&#x636E;targetSDK&#x7684;&#x4E0D;&#x540C;&#xFF0C;&#x5728;&#x591A;&#x7A97;&#x53E3;&#x6A21;&#x5F0F;&#x4E0B;&#x4F1A;&#x6709;&#x622A;&#x7136;&#x4E0D;&#x540C;&#x7684;&#x8868;&#x73B0;&#x3002;&#x5982;&#x679C;targetSDK&#x662F;23&#x53CA;&#x4EE5;&#x4E0B;&#xFF0C;&#x6240;&#x6709;&#x6307;&#x5B9A;&#x4E86;&#x8FD9;&#x4E2A;&#x5C5E;&#x6027;&#x7684;activity&#x90FD;&#x4E0D;&#x652F;&#x6301;&#x591A;&#x7A97;&#x53E3;&#x6A21;&#x5F0F;&#xFF0C;&#x53EA;&#x80FD;&#x4EE5;&#x5168;&#x5C4F;&#x72B6;&#x6001;&#x542F;&#x52A8;&#x3002;&#x5982;&#x679C;targetSDK&#x662F;24&#x53CA;&#x4EE5;&#x4E0A;&#xFF0C;&#x90A3;&#x4E48;&#x5373;&#x4F7F;&#x6307;&#x5B9A;&#x4E86;&#x8FD9;&#x4E2A;&#x5C5E;&#x6027;&#xFF0C;&#x4E5F;&#x53EF;&#x4EE5;&#x8FDB;&#x5165;&#x591A;&#x7A97;&#x53E3;&#x6A21;&#x5F0F;&#xFF0C;&#x4F46;&#x662F;&#x5728;&#x591A;&#x7A97;&#x53E3;&#x6A21;&#x5F0F;&#x4E2D;&#xFF0C;&#x8FD9;&#x4E2A;&#x5C5E;&#x6027;&#x4F1A;&#x88AB;&#x5FFD;&#x7565;&#x3002;&#x8FD9;&#x91CC;&#x8981;&#x6CE8;&#x610F;&#x7684;&#x662F;&#xFF0C;&#x4E00;&#x65E6;&#x8FDB;&#x5165;&#x4E86;&#x591A;&#x7A97;&#x53E3;&#x6A21;&#x5F0F;&#xFF0C;&#x90A3;&#x4E48;&#x5728;&#x4EE3;&#x7801;&#x4E2D;&#x5C31;&#x65E0;&#x6CD5;&#x4F7F;&#x7528;<strong>setRequestedOrientation()</strong> &#x6765;&#x9501;&#x5B9A;&#x5C4F;&#x5E55;&#x65B9;&#x5411;&#x4E86;&#xFF0C;&#x65E0;&#x8BBA;targetSDK&#x662F;&#x4EC0;&#x4E48;&#x7248;&#x672C;&#x90FD;&#x6CA1;&#x6709;&#x6548;&#x679C;&#x3002;<br>
&#x4E00;&#x4E9B;<strong>System UI</strong>&#x76F8;&#x5173;&#x7684;&#x7279;&#x6027;&#x5728;&#x591A;&#x7A97;&#x53E3;&#x6A21;&#x5F0F;&#x4E0B;&#x4E5F;&#x662F;&#x65E0;&#x6548;&#x7684;&#xFF0C;&#x5982;&#x679C;&#x662F;&#x5728;Manifest&#x91CC;&#x914D;&#x7F6E;&#x7684;&#x5C5E;&#x6027;&#xFF0C;&#x53EF;&#x80FD;&#x8FD8;&#x4F1A;&#x5F71;&#x54CD;&#x5E94;&#x7528;&#x65E0;&#x6CD5;&#x8FDB;&#x5165;&#x591A;&#x7A97;&#x53E3;&#x6A21;&#x5F0F;&#xFF0C;&#x6BD4;&#x5982;<code>android:immersive</code>&#xFF0C;&#x89C4;&#x5219;&#x540C;android:screenOrientation&#x3002;</p>
<h4 id>&#x591A;&#x7A97;&#x53E3;&#x6A21;&#x5F0F;&#x7684;&#x751F;&#x547D;&#x5468;&#x671F;</h4>
<p>&#x591A;&#x7A97;&#x53E3;&#x6A21;&#x5F0F;&#x7684;&#x5F15;&#x5165;&#xFF0C;&#x5E76;&#x6CA1;&#x6709;&#x6539;&#x53D8;activity&#x7684;&#x751F;&#x547D;&#x5468;&#x671F;&#xFF0C;&#x4F46;&#x662F;&#x66F4;&#x5F3A;&#x8C03;&#x4E86;<strong>RESUMED</strong>&#x72B6;&#x6001;&#x548C;<strong>STARTED</strong>&#x72B6;&#x6001;&#x7684;&#x533A;&#x522B;&#x3002;&#x4E4B;&#x524D;&#x6211;&#x5BF9;&#x4E8E;STARTED&#x72B6;&#x6001;&#x7684;&#x7406;&#x89E3;&#x662F;&#xFF0C;activity&#x5BF9;&#x7528;&#x6237;&#x53EF;&#x89C1;&#xFF0C;&#x800C;RESUMED&#x662F;&#x83B7;&#x53D6;&#x4E86;&#x7126;&#x70B9;&#x3002;&#x5982;&#x679C;&#x6CA1;&#x6709;&#x591A;&#x7A97;&#x53E3;&#x6A21;&#x5F0F;&#xFF0C;&#x90A3;&#x4E48;&#x8FD9;&#x4E24;&#x4E2A;&#x72B6;&#x6001;&#x4E00;&#x822C;&#x6CA1;&#x6709;&#x4EC0;&#x4E48;&#x533A;&#x522B;&#xFF0C;&#x4F46;&#x662F;&#x5728;&#x591A;&#x7A97;&#x53E3;&#x6A21;&#x5F0F;&#x4E0B;&#xFF0C;&#x5C31;&#x5FC5;&#x7136;&#x4F1A;&#x51FA;&#x73B0;&#x4E00;&#x4E2A;activity&#x5BF9;&#x7528;&#x6237;&#x53EF;&#x89C1;&#xFF0C;&#x4F46;&#x662F;&#x5E76;&#x6CA1;&#x6709;&#x83B7;&#x53D6;&#x7126;&#x70B9;&#x7684;&#x60C5;&#x51B5;&#x3002;&#x6C38;&#x8FDC;&#x90FD;&#x53EA;&#x6709;&#x4E00;&#x4E2A;activity&#x4F1A;&#x5904;&#x4E8E;RESUMED&#x72B6;&#x6001;&#xFF0C;&#x4F46;&#x662F;&#x53E6;&#x4E00;&#x4E2A;activity&#x5373;&#x4F7F;&#x53EA;&#x662F;&#x5904;&#x4E8E;STARTED&#x72B6;&#x6001;&#xFF0C;&#x4F18;&#x5148;&#x7EA7;&#x8FD8;&#x662F;&#x6BD4;&#x4E0D;&#x53EF;&#x89C1;&#x7684;activity&#x8981;&#x9AD8;&#x7684;&#x3002;<br>
&#x5F53;activity&#x5728;&#x591A;&#x7A97;&#x53E3;&#x6A21;&#x5F0F;&#x548C;&#x5168;&#x5C4F;&#x72B6;&#x6001;&#x4E0B;&#x4E92;&#x76F8;&#x5207;&#x6362;&#xFF0C;&#x6216;&#x8005;freeform&#x6A21;&#x5F0F;&#x4E0B;&#x88AB;&#x8C03;&#x6574;&#x5927;&#x5C0F;&#x65F6;&#xFF0C;&#x7CFB;&#x7EDF;&#x4F1A;&#x7ED9;activity&#x4E00;&#x4E2A;&#x914D;&#x7F6E;&#x53D8;&#x5316;&#x7684;&#x901A;&#x77E5;&#xFF0C;&#x5982;&#x679C;Manifest&#x91CC;&#x6CA1;&#x6709;&#x76D1;&#x542C;&#x5BF9;&#x5E94;&#x7684;&#x914D;&#x7F6E;&#x53D8;&#x5316;&#xFF0C;&#x90A3;&#x4E48;activity&#x5C31;&#x4F1A;&#x88AB;&#x9500;&#x6BC1;&#x91CD;&#x65B0;&#x521B;&#x5EFA;&#xFF0C;&#x5426;&#x5219;activity&#x7684;<strong>onConfigurationChanged()</strong> &#x56DE;&#x8C03;&#x4F1A;&#x88AB;&#x8C03;&#x7528;&#x3002;</p>
<h4 id>&#x751F;&#x547D;&#x5468;&#x671F;&#x9002;&#x914D;</h4>
<p>&#x751F;&#x547D;&#x5468;&#x671F;&#x9002;&#x914D;&#x4E3B;&#x8981;&#x662F;&#x4E24;&#x65B9;&#x9762;&#xFF0C;&#x4E00;&#x662F;&#x5BF9;&#x4E8E;&#x914D;&#x7F6E;&#x53D8;&#x5316;&#x7684;&#x5904;&#x7406;&#xFF0C;&#x4E8C;&#x662F;&#x5BF9;&#x4E8E;STARTED&#x548C;RESUMED&#x72B6;&#x6001;&#x7684;&#x5904;&#x7406;&#x3002;&#x914D;&#x7F6E;&#x53D8;&#x5316;&#x81F3;&#x5C11;&#x8981;&#x76D1;&#x542C;&#x5982;&#x4E0B;&#x56DB;&#x4E2A;&#xFF1A;<code>android:configChanges=&quot;screenSize|smallestScreenSize|screenLayout|orientation&quot;</code>&#xFF0C;&#x7136;&#x540E;&#x5728;<strong>onConfigurationChanged()</strong> &#x56DE;&#x8C03;&#x4E2D;&#xFF0C;&#x53EF;&#x4EE5;&#x7528;<strong>isInMultiWindowMode()</strong> &#x65B9;&#x6CD5;&#x6765;&#x5224;&#x65AD;&#x5F53;&#x524D;Activity&#x662F;&#x5426;&#x5904;&#x4E8E;&#x591A;&#x7A97;&#x53E3;&#x6A21;&#x5F0F;&#xFF0C;&#x5E76;&#x4F5C;&#x76F8;&#x5E94;&#x7684;&#x5904;&#x7406;&#x3002;&#x5F53;&#x7528;&#x6237;&#x5728;&#x591A;&#x7A97;&#x53E3;&#x6A21;&#x5F0F;&#x548C;&#x5168;&#x5C4F;&#x6A21;&#x5F0F;&#x5207;&#x6362;&#xFF0C;&#x6216;&#x8005;&#x8C03;&#x6574;&#x7A97;&#x53E3;&#x5927;&#x5C0F;&#x65F6;&#xFF0C;&#x90FD;&#x4F1A;&#x8C03;&#x7528;onConfigurationChanged()&#x56DE;&#x8C03;&#x65B9;&#x6CD5;&#x3002;&#x5982;&#x679C;&#x662F;&#x4E00;&#x4E9B;&#x548C;&#x7528;&#x6237;&#x6709;&#x6301;&#x7EED;&#x6027;&#x4EA4;&#x4E92;&#x7684;Activity&#xFF0C;&#x6BD4;&#x5982;&#x97F3;&#x9891;&#x548C;&#x89C6;&#x9891;&#x7B49;&#xFF0C;&#x90A3;&#x4E48;&#x8981;&#x6CE8;&#x610F;&#xFF0C;&#x5F00;&#x59CB;&#x548C;&#x6682;&#x505C;&#x64AD;&#x653E;&#x8981;&#x5206;&#x522B;&#x653E;&#x5728;<strong>onStart()</strong> &#x548C;<strong>onStop()</strong> &#x56DE;&#x8C03;&#x4E2D;&#xFF0C;&#x800C;&#x4E0D;&#x662F;<strong>onResume()</strong> &#x548C; <strong>onPause()</strong> &#x4E2D;&#x3002;</p>
<h4 id="ui">UI&#x9002;&#x914D;</h4>
<p>&#x56E0;&#x4E3A;freeform&#x6A21;&#x5F0F;&#x7684;&#x5F15;&#x5165;&#xFF0C;activity&#x53EF;&#x7528;&#x7684;&#x7A97;&#x53E3;&#x5927;&#x5C0F;&#x53EF;&#x4EE5;&#x4EE5;&#x4EFB;&#x610F;&#x6BD4;&#x4F8B;&#x53D8;&#x5316;&#xFF0C;&#x8FD9;&#x5C31;&#x8981;&#x6C42;&#x6211;&#x4EEC;&#x7684;&#x5E03;&#x5C40;&#x662F;&#x54CD;&#x5E94;&#x5F0F;&#x7684;&#xFF0C;&#x80FD;&#x591F;&#x9002;&#x5E94;&#x4E0D;&#x540C;&#x7684;&#x5C4F;&#x5E55;&#x5927;&#x5C0F;&#x548C;&#x6BD4;&#x4F8B;&#x3002;&#x603B;&#x7ED3;&#x4E86;&#x4E00;&#x4E0B;&#xFF0C;&#x4E3B;&#x8981;&#x6709;&#x4EE5;&#x4E0B;&#x51E0;&#x6761;&#x5EFA;&#x8BAE;&#xFF1A;</p>
<ol>
<li>&#x907F;&#x514D;hard-code&#x7684;&#x5BBD;&#x9AD8;&#xFF0C;&#x5982;&#x679C;&#x4E0D;&#x662F;ConstraintLayout&#x7684;&#x8BDD;&#xFF0C;&#x5C3D;&#x91CF;&#x7528;wrap_content&#x548C;match_parent&#x6765;&#x63CF;&#x8FF0;&#x5BBD;&#x9AD8;&#x3002;</li>
<li>&#x5982;&#x679C;&#x662F;LinearLayout&#xFF0C;&#x53EF;&#x4EE5;&#x5C1D;&#x8BD5;&#x8BBE;&#x7F6E;layout_weight&#x6765;&#x81EA;&#x9002;&#x5E94;&#x5C4F;&#x5E55;&#xFF0C;&#x4F46;&#x662F;&#x8FD9;&#x6837;&#x4F1A;&#x964D;&#x4F4E;&#x6027;&#x80FD;&#xFF0C;&#x7CFB;&#x7EDF;&#x5728;layout&#x65F6;&#x9700;&#x8981;&#x66F4;&#x591A;&#x7684;&#x8BA1;&#x7B97;&#xFF0C;&#x6700;&#x597D;&#x7528;ConstraintLayout&#x66FF;&#x4EE3;&#x3002;</li>
<li>&#x4F7F;&#x7528;&#x6700;&#x5C0F;&#x5BBD;&#x5EA6;&#x63CF;&#x8FF0;&#x7B26;&#x6765;&#x63D0;&#x4F9B;&#x4E0D;&#x540C;&#x7684;layout&#xFF0C;&#x6BD4;&#x5982;&#x53EF;&#x4EE5;&#x63D0;&#x4F9B;&#x4E00;&#x4E2A;layout-sw320dp&#x6765;&#x9002;&#x914D;&#x6B63;&#x5E38;&#x975E;&#x591A;&#x7A97;&#x53E3;&#x6A21;&#x5F0F;&#x4E0B;&#x7684;&#x60C5;&#x51B5;&#xFF0C;&#x8FD9;&#x91CC;&#x8981;&#x6CE8;&#x610F;&#x4E00;&#x4E0B;&#x9002;&#x914D;&#x89C4;&#x5219;&#xFF0C;swdp&#x6307;&#x5B9A;&#x7684;&#x6570;&#x5B57;&#xFF0C;&#x662F;&#x5BBD;&#x548C;&#x9AD8;&#x7684;&#x6700;&#x5C0F;&#x503C;&#xFF0C;&#x53EB;smallest possible width&#x66F4;&#x51C6;&#x786E;&#x4E00;&#x70B9;&#x3002;&#x5982;&#x679C;&#x63D0;&#x4F9B;&#x4E86;&#x591A;&#x4E2A;&#x4E0D;&#x540C;&#x6570;&#x503C;&#x7684;swdp&#xFF0C;&#x7CFB;&#x7EDF;&#x4F1A;&#x4F7F;&#x7528;&#x6700;&#x63A5;&#x8FD1;&#xFF0C;&#x4F46;&#x662F;&#x6CA1;&#x6709;&#x8D85;&#x8FC7;&#x8BBE;&#x5907;&#x5C4F;&#x5E55;&#x5927;&#x5C0F;&#x7684;&#x90A3;&#x4E00;&#x4E2A;&#x3002;freeform&#x6A21;&#x5F0F;&#x4E0B;&#x8C03;&#x6574;&#x7A97;&#x53E3;&#x5927;&#x5C0F;&#x4F1A;&#x89E6;&#x53D1;&#x914D;&#x7F6E;&#x53D8;&#x5316;&#xFF0C;&#x7CFB;&#x7EDF;&#x4F1A;&#x5728;&#x8FD9;&#x4E2A;&#x65F6;&#x5019;&#x8C03;&#x6574;&#x4F7F;&#x7528;&#x7684;layout&#x3002;</li>
<li>&#x5C3D;&#x91CF;&#x4F7F;&#x7528;fragment&#x6765;&#x5B9E;&#x73B0;UI&#x76F8;&#x5173;&#x7684;&#x903B;&#x8F91;&#xFF0C;&#x8FD9;&#x6837;&#x53EF;&#x4EE5;&#x5C3D;&#x53EF;&#x80FD;&#x5730;&#x907F;&#x514D;&#x91CD;&#x590D;&#x4EE3;&#x7801;&#xFF0C;&#x5728;&#x9002;&#x914D;&#x591A;&#x79CD;&#x5C4F;&#x5E55;&#x5927;&#x5C0F;&#x65F6;&#x590D;&#x7528;&#x73B0;&#x6709;&#x7684;&#x903B;&#x8F91;&#x3002;</li>
<li>&#x53EF;&#x80FD;&#x88AB;&#x62C9;&#x4F38;&#x7684;&#x56FE;&#x7247;&#x4F7F;&#x7528;nine-patch&#x5207;&#x56FE;&#x3002;</li>
<li>&#x6700;&#x540E;&#x4E00;&#x6761;&#xFF0C;&#x5C3D;&#x91CF;&#x4F7F;&#x7528;ConstraintLayout&#x5427;&#xFF0C;&#x8FD9;&#x4E2A;Layout&#x57FA;&#x672C;&#x4E0A;&#x53EF;&#x4EE5;&#x5B9E;&#x73B0;&#x6240;&#x6709;&#x7528;LinearLayout&#xFF0C;RelativeLayout&#x548C;FrameLayout&#x5B9E;&#x73B0;&#x7684;&#x5E03;&#x5C40;&#xFF0C;&#x800C;&#x4E14;&#x6709;&#x52A9;&#x4E8E;&#x51CF;&#x5C11;View&#x7684;&#x5C42;&#x7EA7;&#x3002;&#x56E0;&#x4E3A;ConstraintLayout&#x672C;&#x8EAB;&#x7684;&#x673A;&#x5236;&#xFF0C;&#x5199;&#x51FA;&#x6765;&#x7684;&#x5E03;&#x5C40;&#x57FA;&#x672C;&#x4E0A;&#x5929;&#x7136;&#x662F;&#x54CD;&#x5E94;&#x5F0F;&#x7684;&#xFF0C;&#x53EF;&#x4EE5;&#x51CF;&#x5C11;&#x5F88;&#x591A;&#x9002;&#x914D;&#x5DE5;&#x4F5C;&#x3002;</li>
</ol>
<h4 id="layout">layout&#x6807;&#x7B7E;</h4>
<p>&#x9488;&#x5BF9;&#x591A;&#x7A97;&#x53E3;&#x6A21;&#x5F0F;&#xFF0C;Android&#x8FD8;&#x63D0;&#x4F9B;&#x4E86;&lt;layout&gt;&#x6807;&#x7B7E;&#xFF0C;&#x8FD9;&#x4E2A;&#x6807;&#x7B7E;&#x63D0;&#x4F9B;&#x4E86;5&#x4E2A;&#x5C5E;&#x6027;&#x7528;&#x6765;&#x63A7;&#x5236;activity&#x5728;&#x591A;&#x7A97;&#x53E3;&#x6A21;&#x5F0F;&#x4E0B;&#x7684;&#x8868;&#x73B0;&#x3002;<code>android:defaultWidth</code>&#x548C;<code>android:defaultHeight</code>&#x7528;&#x6765;&#x6307;&#x5B9A;&#x5728;freeform&#x6A21;&#x5F0F;&#x4E0B;&#x542F;&#x52A8;&#x65F6;&#x7684;&#x9ED8;&#x8BA4;&#x5BBD;&#x9AD8;&#xFF0C;<code>android:gravity</code>&#x7528;&#x6765;&#x6307;&#x5B9A;&#x5728;freeform&#x6A21;&#x5F0F;&#x4E0B;&#x542F;&#x52A8;&#x65F6;activity&#x7684;&#x521D;&#x59CB;&#x4F4D;&#x7F6E;&#xFF0C;<code>android:minHeight</code>&#x548C;<code>android:minWidth</code>&#x7528;&#x6765;&#x6307;&#x5B9A;&#x5728;&#x591A;&#x7A97;&#x53E3;&#x6A21;&#x5F0F;&#x4E0B;activity&#x7684;&#x6700;&#x5C0F;&#x5BBD;&#x9AD8;&#xFF0C;&#x5982;&#x679C;&#x7528;&#x6237;&#x624B;&#x52A8;&#x8C03;&#x6574;&#x5206;&#x754C;&#x7EBF;&#x5BFC;&#x81F4;&#x7A97;&#x53E3;&#x5927;&#x5C0F;&#x5C0F;&#x4E8E;&#x8FD9;&#x4E2A;&#x6570;&#x503C;&#xFF0C;&#x5F53;&#x5728;split-screen&#x6A21;&#x5F0F;&#x4E0B;&#xFF0C;activity&#x5C06;&#x88AB;&#x88C1;&#x526A;&#xFF0C;canvas&#x4F9D;&#x7136;&#x7EF4;&#x6301;minWidth&#x548C;minHeight&#x7684;&#x5927;&#x5C0F;&#xFF0C;&#x5982;&#x679C;&#x5728;freeform&#x6A21;&#x5F0F;&#x4E0B;&#xFF0C;&#x90A3;&#x4E48;activity&#x662F;&#x65E0;&#x6CD5;&#x88AB;&#x7F29;&#x653E;&#x5230;minWidth&#x548C;minHeight&#x4EE5;&#x4E0B;&#x7684;&#xFF0C;&#x8FD9;&#x4E24;&#x4E2A;&#x5C5E;&#x6027;&#x5728;freeform&#x6A21;&#x5F0F;&#x4E0B;&#x66F4;&#x7B26;&#x5408;&#x5B57;&#x9762;&#x610F;&#x601D;&#x3002;</p>
<h4 id="activity">&#x591A;&#x7A97;&#x53E3;&#x6A21;&#x5F0F;&#x4E0B;&#x542F;&#x52A8;activity</h4>
<p>&#x591A;&#x7A97;&#x53E3;&#x6A21;&#x5F0F;&#x4E0B;&#xFF0C;activity&#x53EF;&#x4EE5;&#x88AB;&#x542F;&#x52A8;&#x5728;&#x53E6;&#x4E00;&#x4E2A;&#x7A97;&#x53E3;&#xFF0C;&#x4F46;&#x662F;&#x8981;&#x540C;&#x65F6;&#x52A0;&#x4E24;&#x4E2A;flag&#xFF1A;</p>
<pre><code>Intent intent = new Intent(this, ActivityB.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.setFlags(Intent.FLAG_ACTIVITY_LAUNCH_ADJACENT);
startActivity(intent);
</code></pre>
<p>&#x8FD9;&#x91CC;&#x4E00;&#x5B9A;&#x8981;&#x52A0;FLAG_ACTIVITY_NEW_TASK&#xFF0C;&#x5426;&#x5219;FLAG_ACTIVITY_LAUNCH_ADJACENT&#x4F1A;&#x88AB;&#x5FFD;&#x7565;&#x3002;</p>
<h4 id>&#x9002;&#x914D;&#x9A8C;&#x8BC1;</h4>
<ol>
<li>&#x5168;&#x5C4F;&#x6A21;&#x5F0F;&#x4E0B;&#x542F;&#x52A8;&#x5E94;&#x7528;&#xFF0C;&#x7136;&#x540E;&#x5207;&#x6362;&#x5230;&#x591A;&#x7A97;&#x53E3;&#x6A21;&#x5F0F;&#xFF0C;&#x770B;&#x662F;&#x5426;&#x8868;&#x73B0;&#x6B63;&#x5E38;&#x3002;</li>
<li>&#x76F4;&#x63A5;&#x4EE5;&#x591A;&#x7A97;&#x53E3;&#x6A21;&#x5F0F;&#x542F;&#x52A8;&#x5E94;&#x7528;&#xFF0C;&#x770B;&#x662F;&#x5426;&#x8868;&#x73B0;&#x6B63;&#x5E38;&#x3002;</li>
<li>&#x591A;&#x7A97;&#x53E3;&#x6A21;&#x5F0F;&#x4E0B;&#x62D6;&#x52A8;&#x5206;&#x754C;&#x7EBF;&#xFF0C;&#x5E94;&#x7528;&#x4E0D;&#x80FD;&#x5D29;&#x6E83;&#xFF0C;&#x5E76;&#x4E14;UI&#x5C55;&#x793A;&#x6B63;&#x5E38;&#xFF0C;&#x8FD9;&#x91CC;&#x8FD8;&#x8981;&#x5173;&#x6CE8;UI&#x91CD;&#x7ED8;&#x662F;&#x5426;&#x5B58;&#x5728;&#x6027;&#x80FD;&#x95EE;&#x9898;&#x3002;</li>
<li>&#x5728;&#x6307;&#x5B9A;&#x4E86;layout&#x6807;&#x7B7E;&#x7684;&#x65F6;&#x5019;&#xFF0C;&#x89C2;&#x5BDF;&#x62D6;&#x52A8;&#x5206;&#x754C;&#x7EBF;&#x65F6;&#x7684;&#x8868;&#x73B0;&#x662F;&#x5426;&#x7B26;&#x5408;&#x9884;&#x671F;&#x3002;</li>
<li>&#x5982;&#x679C;&#x662F;&#x548C;&#x7528;&#x6237;&#x6709;&#x6301;&#x7EED;&#x4EA4;&#x4E92;&#x7684;&#x5E94;&#x7528;&#xFF0C;&#x6BD4;&#x5982;&#x97F3;&#x89C6;&#x9891;&#x64AD;&#x653E;&#xFF0C;&#x6D4F;&#x89C8;&#x5668;&#x7B49;&#xFF0C;&#x68C0;&#x67E5;&#x591A;&#x7A97;&#x53E3;&#x6A21;&#x5F0F;&#x4E0B;&#x72B6;&#x6001;&#x662F;&#x5426;&#x6B63;&#x5E38;&#x3002;</li>
<li>&#x5FEB;&#x901F;&#x62D6;&#x52A8;&#x5206;&#x754C;&#x7EBF;&#xFF0C;&#x68C0;&#x67E5;&#x662F;&#x5426;&#x5B58;&#x5728;&#x5185;&#x5B58;&#x6CC4;&#x6F0F;&#x3002;</li>
</ol>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[CVE-2017-13156漏洞分析（中）]]></title><description><![CDATA[<!--kg-card-begin: markdown--><p>&#x627F;&#x63A5;&#x4E0A;&#x7BC7;&#xFF0C;&#x672C;&#x7BC7;&#x4E3B;&#x8981;&#x4ECB;&#x7ECD;&#x4E00;&#x4E0B;Android&#x7684;&#x7B7E;&#x540D;&#x673A;&#x5236;&#xFF0C;&#x5E76;&#x4ECE;&#x539F;&#x7406;&#x4E0A;&#x5206;&#x6790;&#x4E00;&#x4E0B;&#x4E3A;&#x4EC0;&#x4E48;&#x4F7F;&#x7528;APK Signature Scheme v2&#x7B7E;&#x540D;&#x7684;&#x5E94;&#x7528;&#x5728;Android 7.0&#x4EE5;&#x4E0A;&#x4E0D;</p>]]></description><link>https://shunix.com/janus-two/</link><guid isPermaLink="false">60812ae62b3f873b19511ec2</guid><category><![CDATA[技术文章]]></category><dc:creator><![CDATA[Shunix]]></dc:creator><pubDate>Thu, 28 Dec 2017 11:35:58 GMT</pubDate><content:encoded><![CDATA[<!--kg-card-begin: markdown--><p>&#x627F;&#x63A5;&#x4E0A;&#x7BC7;&#xFF0C;&#x672C;&#x7BC7;&#x4E3B;&#x8981;&#x4ECB;&#x7ECD;&#x4E00;&#x4E0B;Android&#x7684;&#x7B7E;&#x540D;&#x673A;&#x5236;&#xFF0C;&#x5E76;&#x4ECE;&#x539F;&#x7406;&#x4E0A;&#x5206;&#x6790;&#x4E00;&#x4E0B;&#x4E3A;&#x4EC0;&#x4E48;&#x4F7F;&#x7528;APK Signature Scheme v2&#x7B7E;&#x540D;&#x7684;&#x5E94;&#x7528;&#x5728;Android 7.0&#x4EE5;&#x4E0A;&#x4E0D;&#x53D7;&#x6F0F;&#x6D1E;&#x5F71;&#x54CD;&#x3002;Android&#x63D0;&#x4F9B;&#x4E86;&#x4E24;&#x79CD;&#x7B7E;&#x540D;&#x65B9;&#x5F0F;&#xFF0C;&#x4E00;&#x79CD;&#x662F;v1&#x7684;&#x57FA;&#x4E8E;JAR&#x7B7E;&#x540D;&#x7684;&#x65B9;&#x5F0F;&#xFF0C;&#x53E6;&#x4E00;&#x79CD;&#x5C31;&#x662F;APK Signature Scheme v2&#x3002;</p>
<h4 id>&#x7B7E;&#x540D;&#x9A8C;&#x8BC1;&#x65F6;&#x673A;</h4>
<p>&#x9996;&#x5148;&#x770B;&#x4E00;&#x4E0B;<strong>PackageManagerService</strong>&#x7684;&#x4EE3;&#x7801;&#xFF0C;&#x770B;&#x770B;&#x662F;&#x4EC0;&#x4E48;&#x65F6;&#x5019;&#x8FDB;&#x884C;&#x7B7E;&#x540D;&#x9A8C;&#x8BC1;&#x7684;&#x3002;</p>
<script src="https://gist.github.com/shunix/6c8da86c24f3ae9c68628ee9fa6baeff.js"></script>
<p>PMS&#x7684;installPackageLI&#x65B9;&#x6CD5;&#x4F1A;&#x6784;&#x9020;&#x4E00;&#x4E2A;<strong>PackageParser</strong>&#x5BF9;&#x8C61;&#xFF0C;&#x5E76;&#x8C03;&#x7528;collectCertificates&#x65B9;&#x6CD5;&#x6765;&#x9A8C;&#x8BC1;&#x7B7E;&#x540D;&#x3002;</p>
<script src="https://gist.github.com/shunix/e1a36e3859fd5f4fe5a527c6176084d8.js"></script>
<p>&#x8FD9;&#x91CC;&#x53EF;&#x4EE5;&#x770B;&#x5230;&#xFF0C;&#x9996;&#x5148;&#x8981;&#x5BF9;apk&#x6587;&#x4EF6;&#x7684;entry&#x505A;&#x904D;&#x5386;&#xFF0C;&#x5982;&#x679C;&#x9047;&#x5230;entry&#x662F;&#x76EE;&#x5F55;&#xFF0C;&#x6216;&#x8005;&#x662F;<strong>META-INF</strong>&#x6587;&#x4EF6;&#x540D;&#xFF0C;&#x6216;&#x8005;&#x662F;<strong>AndroidManifest.xml</strong>&#x5219;&#x8DF3;&#x8FC7;&#xFF0C;&#x5426;&#x5219;&#x628A;entry&#x52A0;&#x5165;&#x4E00;&#x4E2A;List&#xFF0C;&#x8FD9;&#x4E2A;List&#x4E2D;&#x7684;&#x6BCF;&#x4E00;&#x4E2A;entry&#x5C06;&#x5728;&#x4E0B;&#x4E00;&#x6B65;&#x8FDB;&#x884C;&#x7B7E;&#x540D;&#x9A8C;&#x8BC1;&#x3002;&#x9A8C;&#x8BC1;&#x7B7E;&#x540D;&#x7684;&#x8FC7;&#x7A0B;&#x540E;&#x9762;&#x4F1A;&#x8BF4;&#xFF0C;&#x8FD9;&#x4E00;&#x8282;&#x53EA;&#x662F;&#x8BF4;&#x660E;&#xFF0C;&#x5728;apk&#x5B89;&#x88C5;&#x7684;&#x65F6;&#x5019;&#xFF0C;PMS&#x4F1A;&#x8FDB;&#x884C;&#x7B7E;&#x540D;&#x9A8C;&#x8BC1;&#x3002;</p>
<h4 id="v1">V1&#x7B7E;&#x540D;</h4>
<p>Android&#x5B98;&#x65B9;&#x6587;&#x6863;&#x6709;&#x8BF4;&#xFF0C;&#x5728;APK Signature Scheme v2&#x7B7E;&#x540D;&#x4E4B;&#x524D;&#xFF0C;&#x7B7E;&#x540D;&#x4F7F;&#x7528;&#x7684;&#x662F;&#x57FA;&#x4E8E;JAR&#x7B7E;&#x540D;&#x7684;&#x65B9;&#x5F0F;&#x3002;&#x5173;&#x4E8E;JAR&#x7B7E;&#x540D;&#xFF0C;oracle&#x7684;&#x5B98;&#x65B9;&#x6587;&#x6863;&#x5728;<a href="https://docs.oracle.com/javase/8/docs/technotes/guides/jar/jar.html#Signed_JAR_File">&#x8FD9;&#x91CC;</a>&#x3002;&#x5B98;&#x65B9;&#x6587;&#x6863;&#x6709;&#x70B9;&#x5197;&#x957F;&#xFF0C;&#x8FD9;&#x91CC;&#x7528;&#x4E00;&#x4E2A;&#x4F8B;&#x5B50;&#x6765;&#x8BF4;&#x660E;&#x4E00;&#x4E0B;&#x8FD9;&#x79CD;&#x7B7E;&#x540D;&#x3002;<br>
&#x7B7E;&#x540D;&#x5B8C;&#x7684;JAR&#x5305;&#x4F1A;&#x591A;&#x51FA;&#x4E00;&#x4E2A;&#x76EE;&#x5F55;&#xFF0C;<strong>META-INF</strong>&#xFF0C;&#x91CC;&#x9762;&#x4F1A;&#x591A;&#x51FA;&#x6765;&#x8FD9;&#x4E48;&#x51E0;&#x4E2A;&#x6587;&#x4EF6;:</p>
<ol>
<li><strong>MANIFEST.MF</strong>&#xFF0C;&#x8FD9;&#x4E2A;&#x6587;&#x4EF6;&#x53EA;&#x4F1A;&#x6709;&#x4E00;&#x4E2A;&#xFF0C;&#x662F;zip entry&#x7684;&#x6E05;&#x5355;&#x6587;&#x4EF6;&#x3002;</li>
<li>*<strong>.SF</strong>&#xFF0C;&#x8FD9;&#x4E2A;&#x540E;&#x7F00;&#x7ED3;&#x5C3E;&#x7684;&#x6587;&#x4EF6;&#xFF0C;&#x547D;&#x540D;&#x53EF;&#x4EE5;&#x4EFB;&#x610F;&#xFF0C;&#x56E0;&#x4E3A;JAR&#x5141;&#x8BB8;&#x591A;&#x91CD;&#x7B7E;&#x540D;&#xFF0C;&#x6240;&#x4EE5;&#x8FD9;&#x4E2A;&#x7C7B;&#x578B;&#x7684;&#x6587;&#x4EF6;&#x53EF;&#x80FD;&#x5B58;&#x5728;&#x591A;&#x4E2A;&#xFF0C;&#x6BCF;&#x4E00;&#x4E2A;SF&#x6587;&#x4EF6;&#x5BF9;&#x5E94;&#x4E00;&#x4E2A;&#x7B7E;&#x540D;&#x8005;&#x3002;</li>
<li>*<strong>.RSA</strong>&#xFF0C;&#x8FD9;&#x4E2A;&#x540E;&#x7F00;&#x7ED3;&#x5C3E;&#x7684;&#x6587;&#x4EF6;&#xFF0C;&#x547D;&#x540D;&#x4E5F;&#x662F;&#x4EFB;&#x610F;&#x7684;&#xFF0C;&#x4F46;&#x662F;&#x5FC5;&#x987B;&#x548C;SF&#x6587;&#x4EF6;&#x4E00;&#x4E00;&#x5BF9;&#x5E94;&#xFF0C;&#x6BCF;&#x4E00;&#x4E2A;RSA&#x6587;&#x4EF6;&#x4E5F;&#x5BF9;&#x5E94;&#x7740;&#x4E00;&#x4E2A;&#x7B7E;&#x540D;&#x8005;&#x3002;</li>
</ol>
<p>&#x5148;&#x770B;&#x4E00;&#x4E0B;&#x524D;&#x4E24;&#x4E2A;&#x6587;&#x4EF6;&#x7684;&#x5185;&#x5BB9;&#xFF1A;<br>
<img src="https://raw.githubusercontent.com/shunix/BlogImages/master/20171227_manifest_mf.png" alt="MANIFEST.MF" loading="lazy"><br>
<img src="https://raw.githubusercontent.com/shunix/BlogImages/master/20171227_cert_sf.png" alt="CERT.SF" loading="lazy"><br>
&#x622A;&#x5F97;&#x4E0D;&#x5168;&#xFF0C;&#x4F46;&#x662F;&#x8FD9;&#x4E00;&#x90E8;&#x5206;&#x5DF2;&#x7ECF;&#x53EF;&#x4EE5;&#x8DB3;&#x591F;&#x5206;&#x6790;&#x8FD9;&#x4E24;&#x4E2A;&#x6587;&#x4EF6;&#x7684;&#x4F5C;&#x7528;&#x4E86;&#x3002;&#x5BF9;&#x6BD4;&#x4E24;&#x4E2A;&#x6587;&#x4EF6;&#x7684;&#x5934;&#x90E8;&#xFF0C;&#x6211;&#x4EEC;&#x53D1;&#x73B0;&#xFF0C;SF&#x6587;&#x4EF6;&#x6BD4;MF&#x6587;&#x4EF6;&#x8981;&#x591A;&#x4E24;&#x4E2A;&#x5C5E;&#x6027;&#xFF0C;<strong>SHA1-Digest-Manifest-Main-Attributes</strong>&#x548C;<strong>SHA1-Digest-Manifest</strong><br>
&#xFF0C;&#x800C;&#x5176;&#x4ED6;&#x5185;&#x5BB9;&#x683C;&#x5F0F;&#x662F;&#x4E00;&#x81F4;&#x7684;&#x3002;&#x8FD9;&#x91CC;&#x770B;&#x4E00;&#x4E0B;<strong>jarsigner</strong>&#x7684;&#x6E90;&#x7801;&#x53EF;&#x4EE5;&#x5F88;&#x65B9;&#x4FBF;&#x5730;&#x7406;&#x89E3;&#x8FD9;&#x4E24;&#x4E2A;&#x6587;&#x4EF6;&#x5185;&#x5BB9;&#x3002;</p>
<script src="https://gist.github.com/shunix/18250ac34ba7558c6da36ab40c0da516.js"></script>
<p>&#x8FD9;&#x662F;main&#x65B9;&#x6CD5;&#xFF0C;&#x53EF;&#x4EE5;&#x770B;&#x5230;&#xFF0C;&#x662F;&#x6309;&#x987A;&#x5E8F;&#x5199;&#x5165;MANIFEST.MF, CERT.SF&#x548C;CERT.RSA&#x7684;&#xFF0C;&#x5148;&#x770B;&#x770B;&#x5199;&#x5165;MANIFEST.MF&#x7684;&#x65B9;&#x6CD5;addDigestsToManifest()&#x3002;</p>
<script src="https://gist.github.com/shunix/69c4dbeb1119ee8dcc1902318afedcfd.js"></script>
<p>&#x8FD9;&#x4E2A;&#x65B9;&#x6CD5;&#x4F1A;&#x904D;&#x5386;&#x5F53;&#x524D;zip&#x5305;&#x5185;&#x6240;&#x6709;entry&#xFF0C;&#x5E76;&#x9488;&#x5BF9;&#x6BCF;&#x4E00;&#x9879;&#x751F;&#x6210;&#x4E00;&#x4E2A;SHA1&#x7684;&#x6458;&#x8981;&#xFF0C;&#x548C;&#x6587;&#x4EF6;&#x540D;&#x4E00;&#x8D77;&#x5199;&#x5165;&#x5230;MANIFEST.MF&#x4E2D;&#xFF0C;META-INF&#x4E0B;&#x7684;&#x6587;&#x4EF6;&#x662F;&#x4F8B;&#x5916;&#x7684;&#xFF0C;&#x4E0D;&#x4F1A;&#x751F;&#x6210;&#x6458;&#x8981;&#x4FE1;&#x606F;&#x3002;<strong>MANIFEST.MF&#x4FDD;&#x5B58;&#x4E86;&#x6BCF;&#x4E00;&#x4E2A;zip entry Base64&#x7F16;&#x7801;&#x540E;&#x7684;SHA1&#x6458;&#x8981;</strong>&#x3002;<br>
&#x518D;&#x770B;&#x770B;&#x5199;&#x5165;CERT.SF&#x7684;&#x65B9;&#x6CD5;writeSignatureFile()</p>
<script src="https://gist.github.com/shunix/08840b11de10b0a8145b1ee0ebc5850a.js"></script>
<p><strong>CERT.SF&#x6587;&#x4EF6;&#x5B58;&#x50A8;&#x7684;&#x662F;MANIFEST.SF&#x6587;&#x4EF6;&#x7684;&#x6458;&#x8981;&#x4FE1;&#x606F;</strong>&#xFF0C;&#x9996;&#x5148;&#x770B;&#x5934;&#x90E8;SHA1-Digest-Manifest&#xFF0C;&#x770B;&#x4EE3;&#x7801;&#x5F88;&#x5BB9;&#x6613;&#x77E5;&#x9053;&#xFF0C;&#x8FD9;&#x662F;MANIFEST.SF&#x6574;&#x4E2A;&#x6587;&#x4EF6;&#x7684;SHA1&#x6458;&#x8981;&#xFF0C;&#x63A5;&#x4E0B;&#x6765;&#x7684;&#x5FAA;&#x73AF;&#xFF0C;&#x628A;&#x539F;&#x672C;MANIFEST.MF&#x91CC;&#x6BCF;&#x4E00;&#x9879;&#x518D;&#x505A;&#x4E00;&#x6B21;SHA1&#x6458;&#x8981;&#xFF0C;&#x4EE5;&#x540C;&#x6837;&#x7684;&#x683C;&#x5F0F;&#x5199;&#x5165;CERT.SF&#x3002;&#x6240;&#x4EE5;&#x8868;&#x9762;&#x4E0A;&#x770B;&#x8D77;&#x6765;CERT.SF&#x548C;MANIFEST.SF&#x683C;&#x5F0F;&#x5DEE;&#x4E0D;&#x591A;&#xFF0C;&#x4F46;&#x5176;&#x5B9E;&#x5728;&#x8BC1;&#x4E66;&#x6821;&#x9A8C;&#x4E2D;&#x7684;&#x4F5C;&#x7528;&#x5B8C;&#x5168;&#x4E0D;&#x540C;&#x3002;<br>
&#x6700;&#x540E;&#x6765;&#x770B;&#x4E00;&#x4E0B;CERT.RSA&#x6587;&#x4EF6;&#xFF0C;&#x8FD9;&#x662F;&#x4E2A;&#x4E8C;&#x8FDB;&#x5236;&#x6587;&#x4EF6;&#xFF0C;&#x6240;&#x4EE5;&#x6211;&#x4EEC;&#x9700;&#x8981;&#x501F;&#x52A9;OpenSSL&#x6765;&#x89E3;&#x6790;&#x3002;<br>
<img src="https://raw.githubusercontent.com/shunix/BlogImages/master/20171227_cert_rsa.png" alt="CERT.RSA" loading="lazy"><br>
&#x663E;&#x7136;&#xFF0C;&#x8FD9;&#x5305;&#x542B;&#x4E86;X509&#x7684;&#x8BC1;&#x4E66;&#xFF0C;&#x6709;&#x516C;&#x94A5;&#xFF0C;&#x52A0;&#x5BC6;&#x7B97;&#x6CD5;&#xFF0C;&#x6709;&#x6548;&#x671F;&#xFF0C;&#x7B7E;&#x53D1;&#x8005;&#x7B49;&#x4FE1;&#x606F;&#x3002;&#x8BA9;&#x6211;&#x4EEC;&#x770B;&#x770B;&#x751F;&#x6210;&#x8FD9;&#x4E2A;&#x6587;&#x4EF6;&#x7684;&#x4EE3;&#x7801;&#xFF1A;</p>
<script src="https://gist.github.com/shunix/467666a84d08e797c6a92497d3af4066.js"></script>
<p>writeSignatureBlock&#x65B9;&#x6CD5;&#x4F1A;&#x5C06;&#x7528;&#x79C1;&#x94A5;&#x52A0;&#x5BC6;&#x540E;&#x7684;CERT.SF&#xFF0C;&#x4EE5;&#x53CA;&#x5305;&#x542B;&#x4E86;&#x516C;&#x94A5;&#x7684;&#x6570;&#x5B57;&#x8BC1;&#x4E66;&#x4E00;&#x8D77;&#x5199;&#x5165;&#x5230;CERT.RSA&#x6587;&#x4EF6;&#xFF0C;&#x8FD9;&#x4E2A;&#x6587;&#x4EF6;&#x7B26;&#x5408;PKCS7&#x683C;&#x5F0F;&#x3002;</p>
<h4 id="v1">V1&#x7B7E;&#x540D;&#x7684;&#x9A8C;&#x8BC1;</h4>
<p>&#x6709;&#x4E86;&#x4E0A;&#x9762;&#x7684;&#x80CC;&#x666F;&#x77E5;&#x8BC6;&#xFF0C;&#x518D;&#x6765;&#x770B;Android&#x5BF9;&#x4E8E;apk&#x5BF9;V1&#x7B7E;&#x540D;&#x7684;&#x9A8C;&#x8BC1;&#xFF0C;&#x5C31;&#x4E0D;&#x96BE;&#x7406;&#x89E3;&#x4E86;&#xFF0C;&#x8D34;&#x4EE3;&#x7801;&#xFF1A;</p>
<script src="https://gist.github.com/shunix/0b412e44131bd6e9646f04186ddcb5ab.js"></script>
<p>&#x4E2D;&#x95F4;&#x8FC7;&#x7A0B;&#x8FC7;&#x4E8E;&#x5197;&#x957F;&#xFF0C;&#x8FD9;&#x91CC;&#x76F4;&#x63A5;&#x7ED9;&#x7ED3;&#x8BBA;&#xFF0C;Android&#x5BF9;&#x4E8E;V1&#x7B7E;&#x540D;&#x7684;&#x9A8C;&#x8BC1;&#xFF0C;&#x4E3B;&#x8981;&#x5206;&#x4EE5;&#x4E0B;&#x51E0;&#x4E2A;&#x6B65;&#x9AA4;&#xFF1A;</p>
<ol>
<li>&#x5BF9;apk&#x6587;&#x4EF6;&#x4E2D;&#x6BCF;&#x4E2A;file entry&#x505A;SHA1&#x6458;&#x8981;&#xFF0C;Base64&#x7F16;&#x7801;&#x540E;&#x4E0E;MANIFEST.MF&#x4E2D;&#x5185;&#x5BB9;&#x6BD4;&#x5BF9;&#x3002;</li>
<li>&#x5BF9;RSA&#x548C;SF&#x6587;&#x4EF6;&#x8FDB;&#x884C;&#x6821;&#x9A8C;&#xFF0C;&#x56E0;&#x4E3A;RSA&#x6587;&#x4EF6;&#x4E2D;&#xFF0C;&#x6709;&#x79C1;&#x94A5;&#x52A0;&#x5BC6;&#x540E;&#x7684;&#x7B7E;&#x540D;&#xFF0C;&#x8FD8;&#x6709;&#x516C;&#x94A5;&#xFF0C;&#x6240;&#x4EE5;&#x53EF;&#x4EE5;&#x6839;&#x636E;&#x516C;&#x94A5;&#x89E3;&#x7B7E;&#x540D;&#xFF0C;&#x8FD9;&#x91CC;&#x5E94;&#x8BE5;&#x80FD;&#x5F97;&#x5230;CERT.SF&#x7684;SHA1&#x6458;&#x8981;&#xFF0C;&#x8DDF;&#x5F53;&#x524D;CERT.SF&#x505A;&#x6BD4;&#x8F83;&#x5C31;&#x53EF;&#x4EE5;&#x77E5;&#x9053;CERT.SF&#x6709;&#x6CA1;&#x6709;&#x88AB;&#x7BE1;&#x6539;&#x3002;</li>
<li>&#x6BD4;&#x5BF9;MANIFEST.MF&#x6574;&#x4E2A;&#x6587;&#x4EF6;&#x7684;SHA1&#x6458;&#x8981;&#xFF0C;&#x770B;&#x662F;&#x5426;&#x548C;CERT.SF&#x5934;&#x90E8;&#x8BB0;&#x5F55;&#x7684;&#x4E00;&#x81F4;&#xFF0C;&#x7136;&#x540E;&#x518D;&#x9010;&#x6761;&#x6BD4;&#x8F83;MANIFEST.MF&#x6570;&#x636E;&#x9879;&#x7684;&#x6458;&#x8981;&#x662F;&#x5426;&#x548C;CERT.SF&#x5BF9;&#x5E94;&#x6761;&#x76EE;&#x4E00;&#x81F4;&#x3002;&#x8FD9;&#x6837;&#x53EF;&#x4EE5;&#x786E;&#x5B9A;MANIFEST.MF&#x6709;&#x6CA1;&#x6709;&#x88AB;&#x7BE1;&#x6539;&#x3002;</li>
</ol>
<p>&#x8FD9;&#x91CC;&#x53EF;&#x4EE5;&#x770B;&#x51FA;&#xFF0C;&#x57FA;&#x4E8E;JAR&#x7B7E;&#x540D;&#x7684;&#x65B9;&#x6848;&#xFF0C;&#x662F;&#x6709;&#x7F3A;&#x9677;&#x7684;&#xFF0C;<strong>V1&#x7B7E;&#x540D;&#x65B9;&#x6848;&#x662F;&#x5BF9;zip&#x6587;&#x4EF6;&#x7684;entry&#x505A;&#x6821;&#x9A8C;&#xFF0C;&#x5E76;&#x6CA1;&#x6709;&#x6821;&#x9A8C;&#x6574;&#x4E2A;apk&#x662F;&#x5426;&#x88AB;&#x7BE1;&#x6539;</strong>&#x3002;&#x6240;&#x4EE5;&#x5C31;&#x6709;&#x4E86;&#x5F88;&#x591A;&#x5229;&#x7528;&#x8FD9;&#x4E00;&#x70B9;&#x7684;&#x9ED1;&#x79D1;&#x6280;&#xFF0C;&#x6BD4;&#x5982;zipalign&#x5BF9;&#x9F50;&#xFF0C;&#x7F8E;&#x56E2;&#x7684;&#x591A;&#x6E20;&#x9053;&#x6253;&#x5305;&#x65B9;&#x6848;&#xFF0C;&#x5728;apk&#x4F7F;&#x7528;V1&#x7B7E;&#x540D;&#x5B8C;&#x540E;&#x8FD8;&#x662F;&#x53EF;&#x4EE5;&#x505A;&#x4E00;&#x4E9B;&#x4FEE;&#x6539;&#xFF0C;&#x800C;&#x4E0D;&#x5F71;&#x54CD;&#x7B7E;&#x540D;&#x7684;&#x9A8C;&#x8BC1;&#x3002;CVE-2017-13156&#x6F0F;&#x6D1E;&#x4E5F;&#x662F;&#x4E00;&#x6837;&#xFF0C;&#x56E0;&#x4E3A;&#x5E76;&#x6CA1;&#x6709;&#x4FEE;&#x6539;&#x539F;&#x6765;apk&#x6587;&#x4EF6;zip entry&#x7684;&#x6570;&#x636E;&#xFF0C;&#x6240;&#x4EE5;&#x7B7E;&#x540D;&#x9A8C;&#x8BC1;&#x662F;&#x53EF;&#x4EE5;&#x901A;&#x8FC7;&#x7684;&#x3002;</p>
<h4 id="v2">V2&#x7B7E;&#x540D;</h4>
<p>&#x56E0;&#x4E3A;V1&#x7B7E;&#x540D;&#x6709;&#x4EE5;&#x4E0A;&#x7684;&#x7F3A;&#x70B9;&#xFF0C;&#x6240;&#x4EE5;Android&#x5728;7.0&#x4E4B;&#x540E;&#x52A0;&#x5165;&#x4E86;&#x5BF9;V2&#x7B7E;&#x540D;&#x652F;&#x6301;&#x3002;SDK&#x76EE;&#x5F55;&#x4E0B;&#x7684;apksigner&#x5DE5;&#x5177;&#x53EF;&#x4EE5;&#x5B8C;&#x6210;&#x5BF9;APK&#x7684;V2&#x7B7E;&#x540D;&#x3002;V2&#x7B7E;&#x540D;&#x5E76;&#x4E0D;&#x662F;apk&#x6587;&#x4EF6;&#x4E2D;&#x7684;&#x4E00;&#x4E2A;entry&#xFF0C;&#x800C;&#x662F;&#x5728;Central Directory&#x4E4B;&#x524D;&#x7684;&#x4E00;&#x6BB5;block&#xFF0C;&#x8FD9;&#x91CC;&#x501F;&#x9274;&#x4E00;&#x4E0B;Android&#x5B98;&#x65B9;&#x6587;&#x6863;&#x7684;&#x56FE;&#x7247;&#xFF1A;<br>
<img src="https://raw.githubusercontent.com/shunix/BlogImages/master/20171228_sigv2_1.png" alt="SigV2" loading="lazy"><br>
&#x53EF;&#x4EE5;&#x5F88;&#x660E;&#x663E;&#x770B;&#x51FA;&#xFF0C;&#x7B7E;&#x540D;&#x4E4B;&#x540E;&#xFF0C;&#x591A;&#x51FA;&#x4E86;&#x7EA2;&#x8272;&#x7684;&#x90E8;&#x5206;&#xFF0C;&#x7D27;&#x90BB;Central Directory&#x4E4B;&#x524D;&#x3002;&#x4ECE;&#x6E90;&#x7801;&#x6765;&#x770B;&#x4E00;&#x4E0B;&#x8FD9;&#x4E2A;&#x5757;&#x7684;&#x683C;&#x5F0F;&#xFF1A;</p>
<script src="https://gist.github.com/shunix/3bde469a211137836c3ed8058de71d44.js"></script>
<p>&#x7B7E;&#x540D;&#x5757;&#x5206;&#x4E3A;&#x4EE5;&#x4E0B;&#x51E0;&#x4E2A;&#x90E8;&#x5206;&#xFF1A;</p>
<ol>
<li>
<p>uint64&#x7C7B;&#x578B;&#xFF0C;8&#x4E2A;&#x5B57;&#x8282;&#xFF0C;&#x8868;&#x793A;&#x6574;&#x4E2A;block&#x957F;&#x5EA6;</p>
</li>
<li>
<p>&#x591A;&#x4E2A;ID/Value&#x7684;&#x952E;&#x503C;&#x5BF9;</p>
</li>
<li>
<p>&#x548C;&#x7B2C;&#x4E00;&#x4E2A;&#x5B57;&#x6BB5;&#x4E00;&#x6837;&#x7684;&#xFF0C;8&#x5B57;&#x8282;&#x7684;block&#x957F;&#x5EA6;</p>
</li>
<li>
<p>uint128&#x7C7B;&#x578B;&#xFF0C;16&#x5B57;&#x8282;&#x7684;magic number&#xFF0C;&#x5185;&#x5BB9;&#x4E3A;&#x201C;APK Sig Block 42&#x201D;<br>
V2&#x7B7E;&#x540D;block&#x7684;ID&#x4E3A;0x7109871a&#xFF0C;&#x8FD9;&#x6BB5;&#x4EE3;&#x7801;&#x53EA;&#x4ECE;&#x952E;&#x503C;&#x5BF9;pairs&#x4E2D;&#x8BFB;&#x53D6;V2&#x7B7E;&#x540D;&#x5757;&#x7684;&#x5185;&#x5BB9;&#xFF0C;&#x5176;&#x4F59;&#x90E8;&#x5206;&#x4E0D;&#x4F5C;&#x5904;&#x7406;&#x3002;<br>
V2&#x7B7E;&#x540D;&#x5757;&#x7684;&#x5185;&#x5BB9;&#x4E3B;&#x8981;&#x5305;&#x542B;&#x4E86;&#x7B7E;&#x540D;&#xFF0C;&#x516C;&#x94A5;&#x548C;&#x8BC1;&#x4E66;&#xFF0C;&#x751F;&#x6210;V2&#x7B7E;&#x540D;&#x5757;&#x7684;&#x4EE3;&#x7801;&#x6BD4;&#x8F83;&#x5197;&#x957F;&#xFF0C;&#x53EF;&#x4EE5;&#x67E5;&#x770B;&#x6E90;&#x7801;&#xFF0C;&#x8FD9;&#x91CC;&#x603B;&#x7ED3;&#x4E86;&#x4E00;&#x4E0B;&#x6B65;&#x9AA4;&#xFF0C;&#x5148;&#x6765;&#x770B;&#x4E00;&#x5F20;&#x56FE;&#xFF1A;<br>
<img src="https://raw.githubusercontent.com/shunix/BlogImages/master/20171228_apk_sections.png" alt="Apk Sections" loading="lazy"><br>
&#x8FD9;&#x91CC;&#x628A;&#x6574;&#x4E2A;APK&#x6587;&#x4EF6;&#x5206;&#x4E3A;&#x4E86;4&#x4E2A;&#x90E8;&#x5206;&#xFF0C;APK Signing Block&#x662F;&#x5BF9;1&#xFF0C;3&#xFF0C;4&#x7684;&#x6821;&#x9A8C;&#xFF0C;&#x5E76;&#x4E0D;&#x5305;&#x62EC;&#x672C;&#x8EAB;&#x3002;&#x6821;&#x9A8C;&#x503C;&#x7684;&#x8BA1;&#x7B97;&#x6B65;&#x9AA4;&#x5982;&#x4E0B;&#xFF1A;</p>
</li>
<li>
<p>&#x628A;1&#xFF0C;3&#xFF0C;4&#x5206;&#x522B;&#x5206;&#x6210;1M&#x5927;&#x5C0F;&#x7684;&#x8FDE;&#x7EED;&#x6570;&#x636E;&#x5757;</p>
</li>
<li>
<p>&#x5BF9;&#x6BCF;&#x4E00;&#x5757;&#x5206;&#x522B;&#x8BA1;&#x7B97;&#x6458;&#x8981;&#x4FE1;&#x606F;&#xFF0C;&#x6458;&#x8981;&#x7684;&#x8BA1;&#x7B97;&#x65B9;&#x6CD5;&#x662F;&#x628A;0xa5&#xFF0C;&#x6570;&#x636E;&#x5757;&#x5927;&#x5C0F;&#xFF08;&#x5C0F;&#x7AEF;&#x5B57;&#x8282;&#x5E8F;&#xFF09;&#x548C;&#x6570;&#x636E;&#x5757;&#x5185;&#x5BB9;&#x62FC;&#x63A5;&#x8D77;&#x6765;&#x6839;&#x636E;&#x4F20;&#x5165;&#x7684;&#x7B97;&#x6CD5;&#x505A;&#x6458;&#x8981;&#x3002;</p>
</li>
<li>
<p>&#x628A;0xa5&#xFF0C;&#x6570;&#x636E;&#x5757;&#x6570;&#x91CF;&#x548C;&#x6570;&#x636E;&#x5757;&#x7684;&#x6458;&#x8981;&#x62FC;&#x63A5;&#xFF0C;&#x518D;&#x505A;&#x4E00;&#x6B21;&#x6458;&#x8981;</p>
</li>
<li>
<p>&#x6700;&#x540E;&#x8BA1;&#x7B97;&#x51FA;&#x7684;&#x6458;&#x8981;&#x79C1;&#x94A5;&#x52A0;&#x5BC6;&#x540E;&#x5373;&#x4E3A;&#x7B7E;&#x540D;<br>
<img src="https://raw.githubusercontent.com/shunix/BlogImages/master/20171228_apk_integrity_protection.png" alt="Apk integrity protection" loading="lazy"></p>
</li>
</ol>
<p>&#x663E;&#x7136;&#x53EF;&#x4EE5;&#x770B;&#x51FA;&#xFF0C;&#x6574;&#x4E2A;&#x8FC7;&#x7A0B;&#x662F;&#x5F88;&#x5BB9;&#x6613;&#x5E76;&#x884C;&#x7684;&#xFF0C;&#x56E0;&#x4E3A;&#x6570;&#x636E;&#x5757;&#x4E4B;&#x524D;&#x6CA1;&#x6709;&#x5173;&#x8054;&#x6027;&#xFF0C;V2&#x7B7E;&#x540D;&#x540C;&#x65F6;&#x4FDD;&#x62A4;&#x4E86;zip entry&#x548C;Central Directory&#xFF0C;&#x4EFB;&#x4F55;&#x4E00;&#x4E2A;&#x5B57;&#x8282;&#x7684;&#x6539;&#x53D8;&#x90FD;&#x5C06;&#x5BFC;&#x81F4;&#x7B7E;&#x540D;&#x6821;&#x9A8C;&#x5931;&#x8D25;&#x3002;&#x56E0;&#x6B64;CVE-2017-13156&#x6F0F;&#x6D1E;&#x8FD9;&#x79CD;&#x5728;&#x5934;&#x90E8;&#x62FC;&#x63A5;dex&#x6587;&#x4EF6;&#x7684;&#x65B9;&#x5F0F;&#x65E0;&#x6CD5;&#x901A;&#x8FC7;&#x7B7E;&#x540D;&#x9A8C;&#x8BC1;&#x3002;</p>
<h4 id="v2">V2&#x7B7E;&#x540D;&#x7684;&#x9A8C;&#x8BC1;</h4>
<p>&#x8FD9;&#x91CC;&#x53EF;&#x4EE5;&#x770B;&#x4E00;&#x4E0B;PackageParser.collectCertificates&#x65B9;&#x6CD5;&#x5728;Android 7.0&#x4EE5;&#x4E0A;&#x7684;&#x5B9E;&#x73B0;&#xFF1A;</p>
<script src="https://gist.github.com/shunix/94a36f06a56b9b90292e2fffbc1eadde.js"></script>
<p>&#x53EF;&#x4EE5;&#x770B;&#x5230;&#xFF0C;PMS&#x4F1A;&#x5148;&#x5C1D;&#x8BD5;&#x9A8C;&#x8BC1;V2&#x7248;&#x672C;&#x7684;&#x7B7E;&#x540D;&#xFF0C;&#x53EA;&#x6709;V2&#x7248;&#x672C;&#x7B7E;&#x540D;&#x627E;&#x4E0D;&#x5230;&#x65F6;&#xFF0C;&#x624D;&#x4F1A;&#x964D;&#x7EA7;&#x4E3A;&#x9A8C;&#x8BC1;V1&#x7248;&#x672C;&#x7684;&#x7B7E;&#x540D;&#xFF0C;&#x56E0;&#x6B64;&#x540C;&#x65F6;&#x4F7F;&#x7528;&#x4E86;V1&#x548C;V2&#x7B7E;&#x540D;&#x7684;APK&#xFF0C;&#x662F;&#x65E0;&#x6CD5;&#x901A;&#x8FC7;&#x964D;&#x7EA7;&#x7B56;&#x7565;&#x7ED5;&#x8FC7;V2&#x7B7E;&#x540D;&#x7684;&#x6821;&#x9A8C;&#x7684;&#x3002;<br>
&#x8FD9;&#x91CC;&#x518D;&#x770B;&#x4E00;&#x4E0B;&#x6821;&#x9A8C;V2&#x7B7E;&#x540D;&#x7684;&#x4EE3;&#x7801;</p>
<script src="https://gist.github.com/shunix/1face0e2a49b1b75a7d65684067cf70e.js"></script>
<p>findSignature&#x65B9;&#x6CD5;&#x901A;&#x8FC7;&#x627E;&#x5230;EoCD&#x7684;&#x4F4D;&#x7F6E;&#x6765;&#x786E;&#x5B9A;Central Directory&#x7684;&#x4F4D;&#x7F6E;&#xFF0C;&#x4ECE;&#x800C;&#x627E;&#x5230;&#x7B7E;&#x540D;&#x5757;&#x7684;&#x4F4D;&#x7F6E;&#xFF0C;&#x518D;&#x901A;&#x8FC7;&#x4E4B;&#x524D;&#x8D34;&#x8FC7;&#x7684;findApkSignatureSchemeV2Block&#x65B9;&#x6CD5;&#x627E;&#x5230;V2&#x7B7E;&#x540D;&#x5757;&#xFF0C;&#x5E76;&#x83B7;&#x53D6;&#x5176;&#x4E2D;&#x7684;&#x7B7E;&#x540D;&#xFF0C;&#x8BC1;&#x4E66;&#x7B49;&#x4FE1;&#x606F;&#x3002;verify&#x65B9;&#x6CD5;&#x5219;&#x662F;&#x5B8C;&#x6210;&#x771F;&#x6B63;&#x7684;&#x7B7E;&#x540D;&#x6821;&#x9A8C;&#xFF0C;&#x7B7E;&#x540D;&#x6821;&#x9A8C;&#x8FC7;&#x7A0B;&#x65E0;&#x975E;&#x662F;&#x975E;&#x5BF9;&#x79F0;&#x89E3;&#x5BC6;&#x90A3;&#x4E00;&#x5957;&#xFF0C;&#x8FD9;&#x91CC;&#x4E0D;&#x518D;&#x8D58;&#x8FF0;&#x3002;<br>
V2&#x7B7E;&#x540D;&#x5BF9;APK&#x5B8C;&#x6574;&#x6027;&#x63D0;&#x4F9B;&#x4E86;&#x66F4;&#x5168;&#x9762;&#x7684;&#x4FDD;&#x8BC1;&#xFF0C;&#x56E0;&#x6B64;&#x5BF9;&#x4E8E;APK&#x540C;&#x65F6;&#x4F7F;&#x7528;V1&#x548C;V2&#x7B7E;&#x540D;&#x53EF;&#x4EE5;&#x5728;&#x4FDD;&#x8BC1;&#x517C;&#x5BB9;&#x6027;&#x7684;&#x540C;&#x65F6;&#x63D0;&#x9AD8;&#x5B89;&#x5168;&#x6027;&#x3002;<br>
&#x8FD9;&#x91CC;&#x591A;&#x8BF4;&#x4E24;&#x53E5;&#xFF0C;&#x7F8E;&#x56E2;&#x4E4B;&#x524D;&#x7684;&#x591A;&#x6E20;&#x9053;&#x6253;&#x5305;&#x65B9;&#x6848;&#x5728;V2&#x7B7E;&#x540D;&#x673A;&#x5236;&#x4E0B;&#x4E5F;&#x5931;&#x6548;&#x4E86;&#xFF0C;&#x5BF9;&#x4E8E;V2&#x7684;&#x591A;&#x6E20;&#x9053;&#x6253;&#x5305;&#xFF0C;&#x53EA;&#x80FD;&#x5728;&#x7B7E;&#x540D;&#x5757;&#x4E2D;&#x5199;&#x5165;&#x65B0;&#x7684;ID/Value&#x952E;&#x503C;&#x5BF9;&#x6765;&#x5B9E;&#x73B0;&#xFF0C;&#x56E0;&#x4E3A;&#x76EE;&#x524D;&#x5BF9;&#x4E8E;V2&#x7B7E;&#x540D;&#x7684;&#x6821;&#x9A8C;&#xFF0C;&#x53EA;&#x8BC6;&#x522B;&#x4E86;ID&#x4E3A;0x7109871a&#x4E0B;&#x7684;value&#xFF0C;&#x4E0D;&#x8BA4;&#x8BC6;&#x7684;ID&#x4E00;&#x5F8B;&#x4E0D;&#x4F5C;&#x5904;&#x7406;&#x3002;</p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[CVE-2017-13156漏洞分析（上）]]></title><description><![CDATA[<!--kg-card-begin: markdown--><h4 id>&#x524D;&#x8A00;</h4>
<p>CVE-2017-13156&#x662F;&#x4ECA;&#x5E74;Android&#x7206;&#x51FA;&#x7684;&#x6700;&#x4E3A;&#x4E25;&#x91CD;&#x7684;&#x4E00;&#x4E2A;&#x6F0F;&#x6D1E;&#xFF0C;&#x8FD9;&#x4E2A;&#x6F0F;&#x6D1E;&#x5141;&#x8BB8;&#x653B;&#x51FB;&#x8005;&#x7ED5;&#x8FC7;Android&#x7CFB;&#x7EDF;V1&#x7684;&#x7B7E;&#x540D;&#xFF0C;&#x7528;&#x7BE1;&#x6539;&#x8FC7;&#x7684;apk&#x8986;&#x76D6;&#x539F;&#x6709;&#x7684;</p>]]></description><link>https://shunix.com/janus-one/</link><guid isPermaLink="false">60812ae62b3f873b19511ec1</guid><category><![CDATA[技术文章]]></category><dc:creator><![CDATA[Shunix]]></dc:creator><pubDate>Mon, 18 Dec 2017 02:06:26 GMT</pubDate><content:encoded><![CDATA[<!--kg-card-begin: markdown--><h4 id>&#x524D;&#x8A00;</h4>
<p>CVE-2017-13156&#x662F;&#x4ECA;&#x5E74;Android&#x7206;&#x51FA;&#x7684;&#x6700;&#x4E3A;&#x4E25;&#x91CD;&#x7684;&#x4E00;&#x4E2A;&#x6F0F;&#x6D1E;&#xFF0C;&#x8FD9;&#x4E2A;&#x6F0F;&#x6D1E;&#x5141;&#x8BB8;&#x653B;&#x51FB;&#x8005;&#x7ED5;&#x8FC7;Android&#x7CFB;&#x7EDF;V1&#x7684;&#x7B7E;&#x540D;&#xFF0C;&#x7528;&#x7BE1;&#x6539;&#x8FC7;&#x7684;apk&#x8986;&#x76D6;&#x539F;&#x6709;&#x7684;&#x5E94;&#x7528;&#xFF0C;&#x653B;&#x51FB;&#x8005;&#x7684;&#x4EE3;&#x7801;&#x53EF;&#x4EE5;&#x8BBF;&#x95EE;&#x539F;&#x5E94;&#x7528;&#x6240;&#x6709;&#x7684;&#x6570;&#x636E;&#x3002;&#x5F71;&#x54CD;&#x8303;&#x56F4;&#x662F;Android 5.0+&#x3002;&#x8FD9;&#x4E2A;&#x6F0F;&#x6D1E;&#x7684;&#x672C;&#x8D28;&#x539F;&#x56E0;&#x662F;ART&#x5141;&#x8BB8;&#x76F4;&#x63A5;&#x8FD0;&#x884C;&#x4E00;&#x4E2A;dex&#xFF0C;&#x540C;&#x65F6;&#x4E5F;&#x5141;&#x8BB8;&#x8FD0;&#x884C;&#x4E00;&#x4E2A;&#x91CC;&#x9762;&#x5305;&#x542B;dex&#x7684;zip&#x6587;&#x4EF6;&#x3002;&#x800C;&#x56E0;&#x4E3A;dex&#x6587;&#x4EF6;&#x683C;&#x5F0F;&#x548C;zip&#x6587;&#x4EF6;&#x683C;&#x5F0F;&#x7684;&#x95EE;&#x9898;&#xFF0C;&#x4E00;&#x4E2A;&#x6587;&#x4EF6;&#x53EF;&#x4EE5;&#x540C;&#x65F6;&#x662F;&#x5408;&#x6CD5;&#x7684;zip&#x6587;&#x4EF6;&#x548C;&#x5408;&#x6CD5;&#x7684;dex&#x6587;&#x4EF6;&#x3002;&#x6B63;&#x662F;&#x56E0;&#x4E3A;&#x8FD9;&#x79CD;&#x4E8C;&#x4E49;&#x6027;&#xFF0C;&#x8FD9;&#x4E2A;&#x6F0F;&#x6D1E;&#x4E5F;&#x88AB;&#x79F0;&#x4F5C;Janus&#x6F0F;&#x6D1E;&#xFF0C;Janus&#x662F;&#x7F57;&#x9A6C;&#x795E;&#x8BDD;&#x4E2D;&#x7684;&#x53CC;&#x9762;&#x795E;&#xFF0C;&#x5177;&#x6709;&#x524D;&#x540E;&#x4E24;&#x4E2A;&#x9762;&#x5B54;&#x3002;&#x5BF9;&#x4E8E;&#x7279;&#x6B8A;&#x4FEE;&#x6539;&#x8FC7;&#x7684;apk&#x6587;&#x4EF6;&#xFF0C;PackageManagerService&#x628A;&#x5B83;&#x5F53;&#x4F5C;&#x5408;&#x6CD5;&#x7684;apk&#x5B89;&#x88C5;&#xFF0C;&#x800C;ART&#x628A;&#x5B83;&#x89C6;&#x4F5C;&#x5408;&#x6CD5;&#x7684;dex&#x6267;&#x884C;&#xFF0C;&#x8FD9;&#x5C31;&#x662F;&#x4E00;&#x4E2A;&#x6587;&#x4EF6;&#x7684;&#x4E24;&#x4E2A;&#x89C6;&#x89D2;&#x3002;github&#x4E0A;&#x5DF2;&#x7ECF;&#x6709;&#x4EBA;&#x653E;&#x51FA;&#x4E86;&#x8FD9;&#x4E2A;&#x6F0F;&#x6D1E;&#x7684;<a href="https://github.com/V-E-O/PoC/blob/master/CVE-2017-13156/janus.py">PoC</a>&#xFF0C;&#x4EE3;&#x7801;&#x867D;&#x7136;&#x5F88;&#x7B80;&#x5355;&#xFF0C;&#x4F46;&#x662F;&#x770B;&#x61C2;&#x9700;&#x8981;&#x4E00;&#x70B9;&#x80CC;&#x666F;&#x77E5;&#x8BC6;&#xFF0C;&#x4E0B;&#x9762;&#x5C31;&#x4ECE;zip&#x548C;dex&#x7684;&#x6587;&#x4EF6;&#x7ED3;&#x6784;&#x4E0A;&#x6765;&#x89E3;&#x91CA;&#x8FD9;&#x6BB5;&#x4EE3;&#x7801;&#x3002;</p>
<h4 id="zip">Zip&#x6587;&#x4EF6;&#x7ED3;&#x6784;</h4>
<p><img src="https://raw.githubusercontent.com/shunix/BlogImages/master/20171217_zip_file_structure.png" alt="Zip File Structure" loading="lazy"><br>
Zip&#x6587;&#x4EF6;&#x6700;&#x91CD;&#x8981;&#x7684;&#x4E00;&#x4E2A;&#x90E8;&#x5206;&#x5C31;&#x662F;&#x672B;&#x5C3E;&#x7684;Central Directory&#xFF0C;&#x8FD9;&#x4E2A;&#x90E8;&#x5206;&#x53EF;&#x4EE5;&#x7406;&#x89E3;&#x4E3A;Zip&#x6587;&#x4EF6;&#x771F;&#x6B63;&#x7684;&#x6587;&#x4EF6;&#x5934;&#xFF0C;&#x89E3;&#x6790;zip&#x6587;&#x4EF6;&#x90FD;&#x662F;&#x4ECE;&#x8FD9;&#x91CC;&#x5F00;&#x59CB;&#x89E3;&#x6790;&#x7684;&#xFF0C;&#x5B83;&#x5305;&#x542B;&#x4E86;zip&#x6587;&#x4EF6;&#x6BCF;&#x4E00;&#x4E2A;entry&#x7684;&#x6458;&#x8981;&#x4FE1;&#x606F;&#x3002;&#x8FD9;&#x4E2A;&#x90E8;&#x5206;&#x7684;&#x7ED3;&#x6784;&#x5982;&#x4E0B;&#xFF1A;<br>
<img src="https://raw.githubusercontent.com/shunix/BlogImages/master/20171217_central_directory_structure.png" alt="Central Directory Structure" loading="lazy"><br>
&#x8FD9;&#x91CC;&#x5F88;&#x5BB9;&#x6613;&#x770B;&#x51FA;&#x6765;&#xFF0C;Central Directory&#x91CC;&#x6709;&#x591A;&#x4E2A;File header&#xFF0C;&#x800C;&#x6BCF;&#x4E00;&#x4E2A;File data&#x524D;&#x9762;&#x4E5F;&#x6709;&#x4E00;&#x4E2A;local file header&#xFF0C;&#x524D;&#x8005;&#x662F;&#x540E;&#x8005;&#x7684;&#x52A0;&#x5F3A;&#x7248;&#xFF0C;&#x5305;&#x542B;&#x4E86;&#x66F4;&#x8BE6;&#x7EC6;&#x7684;&#x6570;&#x636E;&#x3002;File header&#x7ED3;&#x6784;&#x5982;&#x4E0B;,markdown&#x5236;&#x8868;&#x6BD4;&#x8F83;&#x9EBB;&#x70E6;&#xFF0C;&#x8FD9;&#x91CC;&#x4ECE;&#x7EF4;&#x57FA;&#x767E;&#x79D1;&#x4E0A;&#x622A;&#x4E86;&#x4E00;&#x5F20;&#x56FE;&#xFF1A;<br>
<img src="https://raw.githubusercontent.com/shunix/BlogImages/master/20171217_central_directory_file_header.png" alt="File header" loading="lazy"><br>
&#x8FD9;&#x91CC;&#x9700;&#x8981;&#x6CE8;&#x610F;&#x51E0;&#x4E2A;&#x91CD;&#x8981;&#x7684;&#x5B57;&#x6BB5;&#xFF0C;file header&#x603B;&#x662F;&#x4EE5;magic number <strong>0x02014b50</strong>&#x5F00;&#x5934;&#xFF0C;file header&#x7684;&#x7B2C;42~46&#x5B57;&#x8282;&#x662F;&#x5BF9;&#x5E94;&#x7684;local file header&#x7684;&#x504F;&#x79FB;&#xFF0C;&#x89E3;&#x6790;zip&#x6587;&#x4EF6;&#x7684;&#x65F6;&#x5019;&#x5C31;&#x662F;&#x6839;&#x636E;&#x8FD9;&#x4E2A;&#x5B57;&#x6BB5;&#x627E;&#x5230;&#x6BCF;&#x4E00;&#x4E2A;&#x6587;&#x4EF6;entry&#x7684;&#x3002;<br>
End of central directory record&#x7684;&#x7ED3;&#x6784;&#x5F88;&#x56FA;&#x5B9A;&#xFF0C;&#x56FE;&#x7247;&#x540C;&#x6837;&#x53D6;&#x81EA;&#x7EF4;&#x57FA;&#xFF1A;<br>
<img src="https://raw.githubusercontent.com/shunix/BlogImages/master/20171217_EOCD.png" alt="EOCD" loading="lazy"><br>
EOCD&#x662F;&#x4EE5;magic number <strong>0x06054b50</strong>&#x5F00;&#x5934;&#x7684;&#x4E00;&#x4E2A;&#x6570;&#x636E;&#x5757;&#xFF0C;&#x5176;&#x4E2D;&#x7B2C;12~16&#x5B57;&#x8282;&#x5305;&#x542B;&#x4E86;central directory&#x7684;&#x957F;&#x5EA6;&#xFF0C;16~20&#x5B57;&#x8282;&#x5305;&#x542B;&#x4E86;central directory&#x8D77;&#x59CB;&#x4F4D;&#x7F6E;&#x7684;&#x7EDD;&#x5BF9;&#x504F;&#x79FB;&#x91CF;&#xFF0C;&#x4E3A;&#x4E86;&#x7406;&#x89E3;&#x540E;&#x7EED;&#x7684;&#x5185;&#x5BB9;&#xFF0C;&#x8BF7;&#x7279;&#x522B;&#x7559;&#x610F;&#x8FD9;&#x4E09;&#x4E2A;&#x5B57;&#x6BB5;&#x3002;<br>
&#x770B;&#x5B8C;&#x4E0A;&#x9762;&#x51E0;&#x5F20;&#x56FE;&#xFF0C;&#x6211;&#x4EEC;&#x53EF;&#x4EE5;&#x5F88;&#x5BB9;&#x6613;&#x5730;&#x5F97;&#x51FA;zip&#x6587;&#x4EF6;&#x7684;&#x89E3;&#x6790;&#x6D41;&#x7A0B;:</p>
<ol>
<li>&#x6839;&#x636E;magic number 0x06054b50&#x627E;&#x5230;End of central directory record</li>
<li>&#x6839;&#x636E;End of central directory record&#x4E2D;&#x7B2C;16~20&#x5B57;&#x8282;&#x627E;&#x5230;central directory&#x7684;&#x8D77;&#x59CB;&#x4F4D;&#x7F6E;</li>
<li>&#x4EE5;magic number 0x02014b50&#x4E3A;&#x6807;&#x8BB0;&#x4F4D;&#xFF0C;&#x904D;&#x5386;central directory&#x4E2D;&#x6BCF;&#x4E00;&#x4E2A;file header</li>
<li>&#x6839;&#x636E;file header&#x4E2D;&#x7684;&#x5143;&#x6570;&#x636E;&#x627E;&#x5230;local file header&#x7684;&#x4F4D;&#x7F6E;</li>
<li>&#x6839;&#x636E;local file header&#x7684;&#x5143;&#x6570;&#x636E;&#x89E3;&#x6790;file data</li>
</ol>
<p>zip&#x7684;&#x8FD9;&#x4E2A;&#x7279;&#x6027;&#x4F7F;&#x5F97;&#x89E3;&#x538B;&#x5DE5;&#x5177;&#x5728;&#x4E0D;&#x9700;&#x8981;&#x8BFB;&#x53D6;&#x5B8C;&#x6574;&#x6587;&#x4EF6;&#x5185;&#x5BB9;&#x7684;&#x60C5;&#x51B5;&#x4E0B;&#x5C31;&#x53EF;&#x4EE5;&#x5C55;&#x793A;&#x6574;&#x4E2A;&#x538B;&#x7F29;&#x5305;&#x7684;&#x7ED3;&#x6784;&#x3002;zip&#x6587;&#x4EF6;&#x5B9E;&#x9645;&#x4E0A;&#x7684;&#x6587;&#x4EF6;&#x5934;&#x662F;&#x5728;&#x5C3E;&#x90E8;&#x7684;&#xFF0C;&#x56E0;&#x6B64;&#x5934;&#x90E8;&#x53EF;&#x4EE5;&#x4EFB;&#x610F;&#x62FC;&#x63A5;&#x6570;&#x636E;&#xFF0C;&#x53EA;&#x8981;&#x4FEE;&#x6539;&#x597D;&#x76F8;&#x5E94;&#x7684;&#x504F;&#x79FB;&#x91CF;&#xFF0C;&#x8FD9;&#x4E2A;&#x6587;&#x4EF6;&#x8FD8;&#x662F;&#x4E00;&#x4E2A;&#x5408;&#x6CD5;&#x7684;zip&#x6587;&#x4EF6;&#xFF0C;&#x6BD4;&#x5982;&#x81EA;&#x89E3;&#x538B;&#x7A0B;&#x5E8F;&#x7684;&#x5B9E;&#x73B0;&#xFF0C;&#x5C31;&#x662F;&#x5728;&#x5934;&#x90E8;&#x62FC;&#x4E0A;&#x4E86;exe&#x6587;&#x4EF6;&#x3002;zip&#x683C;&#x5F0F;&#x53EA;&#x8981;&#x6C42;&#x4E86;&#x5E94;&#x7528;&#x5FC5;&#x987B;&#x4ECE;central directory&#x5F00;&#x59CB;&#x89E3;&#x6790;&#x6587;&#x4EF6;&#xFF0C;&#x4F46;&#x662F;&#x5E76;&#x6CA1;&#x6709;&#x8981;&#x6C42;&#x68C0;&#x67E5;&#x6574;&#x4E2A;&#x6587;&#x4EF6;&#x662F;&#x5426;&#x4EE5;0x02014b50&#x5F00;&#x5934;&#xFF0C;&#x4E00;&#x822C;&#x60C5;&#x51B5;&#x4E0B;&#xFF0C;&#x8FD9;&#x5E76;&#x4E0D;&#x4F1A;&#x6709;&#x4EC0;&#x4E48;&#x95EE;&#x9898;&#xFF0C;&#x4F46;&#x662F;&#x7ED3;&#x5408;ART&#x7684;&#x673A;&#x5236;&#x548C;dex&#x7684;&#x6587;&#x4EF6;&#x7ED3;&#x6784;&#xFF0C;&#x5C31;&#x5BFC;&#x81F4;&#x4E86;Janus&#x6F0F;&#x6D1E;&#x3002;</p>
<h4 id="dex">Dex&#x6587;&#x4EF6;&#x7ED3;&#x6784;</h4>
<p>Dex&#x6587;&#x4EF6;&#x7ED3;&#x6784;&#x6CA1;&#x5FC5;&#x8981;&#x4E86;&#x89E3;&#x5F97;&#x90A3;&#x4E48;&#x7EC6;&#x81F4;&#xFF0C;&#x8DDF;&#x672C;&#x6587;&#x6709;&#x5173;&#x7684;&#x53EA;&#x6709;&#x4E00;&#x4E2A;&#x6587;&#x4EF6;&#x5934;&#xFF0C;&#x8FD9;&#x91CC;&#x6211;&#x4ECE;Android&#x5B98;&#x7F51;&#x627E;&#x4E86;&#x4E00;&#x5F20;&#x56FE;&#xFF0C;&#x622A;&#x5F97;&#x4E0D;&#x5168;&#xFF0C;&#x4F46;&#x662F;&#x5BF9;&#x4E8E;&#x672C;&#x6587;&#x8DB3;&#x591F;&#x4E86;:<br>
<img src="https://raw.githubusercontent.com/shunix/BlogImages/master/20171217_dex_file_header.png" alt="Dex file header" loading="lazy"><br>
dex&#x6587;&#x4EF6;&#x603B;&#x662F;&#x4EE5;magic number <strong>DEX_FILE_MAGIC</strong>&#x5F00;&#x5934;&#xFF0C;&#x8FD9;&#x4E2A;&#x503C;&#x662F;**{ 0x64 0x65 0x78 0x0a 0x30 0x33 0x38 0x00 }<strong>&#xFF0C;&#x5199;&#x6210;ASCII&#x7684;&#x8868;&#x793A;&#x5C31;&#x662F;&#x6211;&#x4EEC;&#x5E73;&#x65F6;&#x770B;&#x5230;&#x7684;</strong>&quot;dex\n038\0&quot;**&#x3002;&#x6211;&#x4EEC;&#x53EA;&#x9700;&#x8981;&#x5173;&#x6CE8;dex&#x6587;&#x4EF6;&#x5934;&#x7684;&#x524D;4&#x4E2A;&#x5B57;&#x6BB5;&#xFF0C;&#x7B2C;&#x4E00;&#x4E2A;&#x662F;magic number&#xFF0C;&#x5360;8&#x4E2A;&#x5B57;&#x8282;&#xFF0C;&#x7B2C;&#x4E8C;&#x4E2A;&#x662F;dex&#x7684;adler32&#x6821;&#x9A8C;&#x7801;&#xFF0C;&#x5360;4&#x4E2A;&#x5B57;&#x8282;&#xFF0C;&#x7B2C;&#x4E09;&#x4E2A;&#x662F;SHA-1&#x7684;&#x7B7E;&#x540D;&#xFF0C;&#x5360;20&#x4E2A;&#x5B57;&#x8282;&#xFF0C;&#x7B2C;&#x56DB;&#x4E2A;&#x5B57;&#x6BB5;&#x662F;dex&#x6587;&#x4EF6;&#x7684;&#x603B;&#x957F;&#x5EA6;&#xFF0C;&#x5360;4&#x4E2A;&#x5B57;&#x8282;&#x3002;&#x7406;&#x8BBA;&#x4E0A;&#x6765;&#x8BF4;&#xFF0C;&#x540C;&#x65F6;&#x4FEE;&#x6539;&#x8FD9;&#x51E0;&#x4E2A;&#x5B57;&#x6BB5;&#xFF0C;&#x6211;&#x4EEC;&#x5C31;&#x53EF;&#x4EE5;&#x4FDD;&#x6301;&#x4E00;&#x4E2A;dex&#x6587;&#x4EF6;&#x662F;&#x5408;&#x6CD5;&#x7684;&#x3002;</p>
<h4 id="poc">PoC</h4>
<p>&#x597D;&#x4E86;&#xFF0C;&#x6709;&#x4E86;&#x8FD9;&#x4E9B;&#x524D;&#x7F6E;&#x77E5;&#x8BC6;&#xFF0C;&#x5C31;&#x53EF;&#x4EE5;&#x6765;&#x770B;&#x4E00;&#x4E0B;&#x811A;&#x672C;&#x4E86;&#xFF0C;&#x811A;&#x672C;&#x6211;&#x52A0;&#x597D;&#x4E86;&#x6CE8;&#x91CA;&#xFF0C;&#x5E94;&#x8BE5;&#x5F88;&#x5BB9;&#x6613;&#x61C2;&#x3002;</p>
<script src="https://gist.github.com/shunix/7e49bb8720373fb74f06e6d8c9c8323a.js"></script>
<h4 id>&#x5B98;&#x65B9;&#x4FEE;&#x590D;</h4>
<p>PackageManagerService&#x5B89;&#x88C5;&#x5E94;&#x7528;&#x7684;&#x65F6;&#x5019;&#xFF0C;&#x4F1A;&#x4F7F;&#x7528;PackageParser&#x8FD9;&#x4E2A;&#x7C7B;&#x53BB;&#x89E3;&#x6790;apk&#x5305;&#xFF0C;&#x800C;Android 5.0&#x4EE5;&#x4E0A;&#x7684;PackageParser&#x89E3;&#x6790;apk&#x7684;&#x65F6;&#x5019;&#xFF0C;&#x4F7F;&#x7528;&#x7684;&#x662F;StrictJarFile&#x7C7B;&#xFF0C;&#x8FD9;&#x4E2A;&#x7C7B;&#x5176;&#x5B9E;&#x662F;&#x4E00;&#x4E2A;jni&#x7684;wrapper&#xFF0C;&#x771F;&#x6B63;&#x7684;&#x5B9E;&#x73B0;&#x8981;&#x770B;zip_archive.cc.&#x6211;&#x4EEC;&#x5148;&#x6765;&#x770B;&#x4E00;&#x4E0B;Google&#x5BF9;&#x4E8E;&#x8FD9;&#x4E2A;&#x6F0F;&#x6D1E;&#x7684;&#x4FEE;&#x590D;&#xFF1A;</p>
<script src="https://gist.github.com/shunix/f8747d3e4f3d8cafd7c3f4c6cd564895.js"></script>
<p>Google&#x5728;&#x89E3;&#x6790;zip&#x6587;&#x4EF6;&#x7684;Central Directory&#x7684;&#x65F6;&#x5019;&#x52A0;&#x4E0A;&#x4E86;&#x5BF9;&#x6587;&#x4EF6;&#x5934;&#x7684;&#x5224;&#x65AD;&#xFF0C;&#x5982;&#x679C;&#x4E0D;&#x662F;&#x4EE5;&#x7279;&#x5B9A;&#x7684;magic number&#x5F00;&#x5934;&#xFF0C;&#x5219;&#x8FD4;&#x56DE;&#x9519;&#x8BEF;&#x3002;&#x800C;&#x5728;&#x8FD9;&#x4E4B;&#x524D;&#xFF0C;zip_archive.cc&#x662F;&#x76F4;&#x63A5;&#x89E3;&#x6790;Central Directory&#x7684;&#xFF0C;&#x5E76;&#x6CA1;&#x6709;&#x9A8C;&#x8BC1;&#x6587;&#x4EF6;&#x5934;&#x90E8;&#x51E0;&#x4E2A;&#x5B57;&#x8282;&#xFF0C;&#x4F7F;&#x7528;PoC&#x811A;&#x672C;&#x4FEE;&#x6539;&#x8FC7;&#x7684;apk&#x6587;&#x4EF6;&#x53EF;&#x4EE5;&#x987A;&#x5229;&#x5B8C;&#x6210;&#x89E3;&#x6790;&#xFF0C;&#x8986;&#x76D6;&#x6389;&#x539F;&#x6709;&#x5E94;&#x7528;&#x3002;</p>
<h4 id>&#x540E;&#x8BB0;</h4>
<p>&#x540E;&#x9762;&#x8FD8;&#x4F1A;&#x6709;&#x4E24;&#x7BC7;&#xFF0C;&#x5206;&#x522B;&#x5206;&#x6790;ART&#x4E3A;&#x4EC0;&#x4E48;&#x4F1A;&#x5148;&#x6267;&#x884C;&#x4FEE;&#x6539;&#x540E;&#x62FC;&#x5728;&#x5934;&#x90E8;&#x7684;dex&#x6587;&#x4EF6;&#x548C;Android V2&#x7B7E;&#x540D;&#x4E3A;&#x4EC0;&#x4E48;&#x4E0D;&#x53D7;&#x8FD9;&#x4E2A;&#x6F0F;&#x6D1E;&#x7684;&#x5F71;&#x54CD;&#x3002;&#x65F6;&#x95F4;&#x5173;&#x7CFB;&#xFF0C;&#x5148;&#x5199;&#x4E86;&#x8FD9;&#x4E00;&#x7BC7;&#x3002;</p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[SharedPreferences源码分析]]></title><description><![CDATA[<!--kg-card-begin: markdown--><h4 id>&#x524D;&#x8A00;</h4>
<p>SharedPreferences&#x4F5C;&#x4E3A;Android&#x5E94;&#x7528;&#x914D;&#x7F6E;&#x9879;&#x7684;&#x5B58;&#x50A8;&#xFF0C;&#x7ED9;&#x4E0A;&#x5C42;&#x63D0;&#x4F9B;&#x4E86;&#x975E;&#x5E38;&#x65B9;&#x4FBF;&#x7684;&#x63A5;&#x53E3;&#xFF0C;&#x8FD9;&#x7BC7;Post&#x5C06;&#x4ECE;&#x6E90;&#x7801;&#x5C42;&#x9762;&#x5206;&#x6790;SharedPreferences&#x5B9E;&#x73B0;&#x7684;&#x7EC6;&#x8282;&#x3002;</p>
<h4 id="sharedpreferences">&#x83B7;&#x53D6;SharedPreferences</h4>]]></description><link>https://shunix.com/analyze-sharedpreferences-source-code/</link><guid isPermaLink="false">60812ae62b3f873b19511ec0</guid><category><![CDATA[技术文章]]></category><dc:creator><![CDATA[Shunix]]></dc:creator><pubDate>Tue, 14 Nov 2017 08:07:56 GMT</pubDate><content:encoded><![CDATA[<!--kg-card-begin: markdown--><h4 id>&#x524D;&#x8A00;</h4>
<p>SharedPreferences&#x4F5C;&#x4E3A;Android&#x5E94;&#x7528;&#x914D;&#x7F6E;&#x9879;&#x7684;&#x5B58;&#x50A8;&#xFF0C;&#x7ED9;&#x4E0A;&#x5C42;&#x63D0;&#x4F9B;&#x4E86;&#x975E;&#x5E38;&#x65B9;&#x4FBF;&#x7684;&#x63A5;&#x53E3;&#xFF0C;&#x8FD9;&#x7BC7;Post&#x5C06;&#x4ECE;&#x6E90;&#x7801;&#x5C42;&#x9762;&#x5206;&#x6790;SharedPreferences&#x5B9E;&#x73B0;&#x7684;&#x7EC6;&#x8282;&#x3002;</p>
<h4 id="sharedpreferences">&#x83B7;&#x53D6;SharedPreferences</h4>
<p>&#x83B7;&#x53D6;SharedPreferences&#x5B9E;&#x4F8B;&#x662F;&#x901A;&#x8FC7;ContextImpl.getSharedPreferences(String name, int mode)&#x65B9;&#x6CD5;&#x6765;&#x5B8C;&#x6210;&#x7684;&#x3002;</p>
<script src="https://gist.github.com/shunix/332c323bd2c4bebfe4c552d5af578ccf.js"></script>
<p>&#x8FD9;&#x91CC;&#x7684;<strong>sSharedPrefs</strong>&#x662F;<strong>ContextImpl</strong>&#x7684;&#x9759;&#x6001;&#x6210;&#x5458;&#xFF0C;&#x7C7B;&#x578B;&#x4E3A;<strong>ArrayMap&lt;String, ArrayMap&lt;String, SharedPreferencesImpl&gt;&gt;</strong>&#xFF0C;&#x4ECE;&#x8FD9;&#x4E2A;ArrayMap&#x91CC;&#xFF0C;&#x6211;&#x4EEC;&#x53EF;&#x4EE5;&#x901A;&#x8FC7;&#x5305;&#x540D;&#x83B7;&#x53D6;&#x53E6;&#x4E00;&#x4E2A;ArrayMap <strong>packagePrefs</strong>&#xFF0C;&#x5176;&#x4E2D;&#x5305;&#x542B;&#x6587;&#x4EF6;&#x540D;&#x5230;<strong>SharedPreferencesImpl</strong>&#x7684;&#x6620;&#x5C04;&#x3002;&#x8FD9;&#x91CC;&#x6211;&#x521D;&#x770B;&#x7684;&#x65F6;&#x5019;&#x4E0D;&#x592A;&#x7406;&#x89E3;&#xFF0C;&#x4E3A;&#x4EC0;&#x4E48;&#x8981;&#x4E24;&#x7EA7;&#x6620;&#x5C04;&#x3002;&#x540E;&#x6765;&#x60F3;&#x4E86;&#x4E00;&#x4E0B;&#xFF0C;&#x5E94;&#x8BE5;&#x662F;&#x9488;&#x5BF9;sharedUserId&#x7684;&#x60C5;&#x51B5;&#xFF0C;&#x8FD9;&#x79CD;&#x60C5;&#x51B5;&#x4E0B;&#xFF0C;&#x540C;&#x4E00;&#x4E2A;&#x8FDB;&#x7A0B;&#x4F1A;&#x6709;&#x4E0D;&#x540C;&#x7684;Context&#x548C;&#x5305;&#x540D;&#xFF0C;&#x4E2A;&#x4EBA;&#x89C1;&#x89E3;&#xFF0C;&#x5982;&#x679C;&#x4E0D;&#x5BF9;&#xFF0C;&#x6B22;&#x8FCE;&#x6307;&#x6B63;&#x3002;<br>
&#x8FD9;&#x91CC;&#x8981;&#x6CE8;&#x610F;&#x5982;&#x4E0B;&#x51E0;&#x70B9;&#xFF1A;</p>
<ol>
<li>ContextImpl&#x5BF9;SharedPreferencesImpl&#x5BF9;&#x8C61;&#x662F;&#x505A;&#x4E86;&#x7F13;&#x5B58;&#x7684;&#xFF0C;&#x56E0;&#x4E3A;&#x662F;&#x9759;&#x6001;&#x6210;&#x5458;&#xFF0C;&#x6240;&#x4EE5;&#x540C;&#x4E00;&#x8FDB;&#x7A0B;&#x5185;&#xFF0C;&#x65E0;&#x8BBA;&#x8C03;&#x7528;&#x591A;&#x5C11;&#x6B21;getSharedPreferences&#x65B9;&#x6CD5;&#xFF0C;&#x8FD4;&#x56DE;&#x7684;&#x5BF9;&#x8C61;&#x90FD;&#x662F;&#x540C;&#x4E00;&#x4E2A;&#x3002;</li>
<li>&#x5982;&#x679C;&#x6307;&#x5B9A;&#x4E86;<strong>MODE_MULTI_PROCESS</strong>&#x7684;flag&#xFF0C;&#x90A3;&#x4E48;&#x6267;&#x884C;startReloadIfChangedUnexpectedly&#x65B9;&#x6CD5;&#xFF0C;&#x8FD9;&#x4E2A;&#x65B9;&#x6CD5;&#x7684;&#x5177;&#x4F53;&#x5185;&#x5BB9;&#x4F1A;&#x5728;&#x540E;&#x9762;&#x5206;&#x6790;&#xFF0C;&#x8FD9;&#x4E2A;&#x65B9;&#x6CD5;&#x7684;&#x5B9E;&#x73B0;&#x4E5F;&#x7B97;&#x662F;SharedPreferences&#x7684;&#x4E00;&#x5927;&#x9ED1;&#x70B9;&#x3002;</li>
</ol>
<h4 id="sharedpreferencesimpl">SharedPreferencesImpl&#x521D;&#x59CB;&#x5316;</h4>
<p>ContextImpl&#x5982;&#x679C;&#x53D1;&#x73B0;&#x8BF7;&#x6C42;&#x7684;SharedPrefernces&#x4E0D;&#x5728;&#x7F13;&#x5B58;&#x4E2D;&#xFF0C;&#x5C31;&#x4F1A;&#x521B;&#x5EFA;&#x65B0;&#x7684;SharedPreferencesImpl&#x5BF9;&#x8C61;&#xFF0C;&#x5E76;&#x52A0;&#x5165;&#x7F13;&#x5B58;&#x3002;</p>
<script src="https://gist.github.com/shunix/96a08c9ef2671caa7be062f66a2396dc.js"></script>
<p>SharedPreferences&#x4ECE;&#x6587;&#x4EF6;&#x52A0;&#x8F7D;&#x5230;&#x78C1;&#x76D8;&#x7684;&#x6D41;&#x7A0B;&#x5982;&#x4E0B;&#xFF1A;</p>
<ol>
<li>&#x628A;<strong>mLoaded</strong>&#x7F6E;&#x4E3A;false&#xFF0C;&#x8FD9;&#x4E2A;&#x53D8;&#x91CF;&#x7528;&#x6765;&#x6807;&#x8BC6;&#x6587;&#x4EF6;&#x662F;&#x5426;&#x5DF2;&#x7ECF;&#x5B8C;&#x6210;&#x4E86;&#x52A0;&#x8F7D;&#xFF0C;&#x5BF9;&#x8FD9;&#x4E2A;&#x53D8;&#x91CF;&#x7684;&#x8BBF;&#x95EE;&#x90FD;&#x662F;&#x4E0A;&#x9501;&#x7684;&#xFF0C;&#x4E00;&#x662F;&#x4E3A;&#x4E86;&#x4FDD;&#x8BC1;&#x53EF;&#x89C1;&#x6027;&#xFF0C;&#x800C;&#x662F;&#x4E3A;&#x4E86;&#x4FDD;&#x8BC1;&#x540C;&#x6B65;&#x3002;&#x7136;&#x540E;&#x65B0;&#x521B;&#x5EFA;&#x4E00;&#x4E2A;&#x7EBF;&#x7A0B;&#xFF0C;&#x771F;&#x6B63;&#x6267;&#x884C;&#x4ECE;&#x78C1;&#x76D8;&#x52A0;&#x8F7D;&#x7684;&#x64CD;&#x4F5C;&#x3002;</li>
<li>&#x5982;&#x679C;&#x68C0;&#x6D4B;&#x5230;&#x5907;&#x4EFD;&#x6587;&#x4EF6;&#x5B58;&#x5728;&#xFF0C;&#x8BF4;&#x660E;&#x5F53;&#x524D;&#x6587;&#x4EF6;<strong>mFile</strong>&#x662F;&#x6709;&#x95EE;&#x9898;&#x7684;&#xFF0C;&#x76F4;&#x63A5;&#x5220;&#x9664;&#xFF0C;&#x5E76;&#x7528;&#x5907;&#x4EFD;&#x6587;&#x4EF6;&#x8986;&#x76D6;&#x5F53;&#x524D;&#x6587;&#x4EF6;&#x3002;</li>
<li>&#x4ECE;XML&#x6587;&#x4EF6;&#x8BFB;&#x51FA;&#x952E;&#x503C;&#x5BF9;&#xFF0C;&#x4FDD;&#x5B58;&#x5728;<strong>mMap</strong>&#x6570;&#x7EC4;&#xFF0C;&#x5E76;&#x8BB0;&#x5F55;&#x4E0B;&#x5F53;&#x524D;&#x6587;&#x4EF6;&#x7684;&#x5927;&#x5C0F;&#x548C;&#x4FEE;&#x6539;&#x65F6;&#x95F4;&#x6233;&#x5230;<strong>mStatSize</strong>&#x548C;<strong>mStatTimestamp</strong>&#x3002;</li>
</ol>
<p>&#x521D;&#x59CB;&#x5316;&#x8FC7;&#x7A0B;&#x5C31;&#x662F;&#x8FD9;&#x6837;&#xFF0C;&#x8FD9;&#x6BB5;&#x4EE3;&#x7801;&#x7B2C;24-26&#x884C;&#x6211;&#x4E2A;&#x4EBA;&#x8BA4;&#x4E3A;&#x662F;&#x591A;&#x4F59;&#x7684;&#xFF0C;&#x53EA;&#x6709;<strong>loadFromDiskLocked()<strong>&#x65B9;&#x6CD5;&#x672C;&#x8EAB;&#x4F1A;&#x628A;</strong>mLoaded</strong>&#x7F6E;&#x4E3A;true&#xFF0C;&#x4F46;&#x662F;&#x8FD9;&#x4E2A;&#x65B9;&#x6CD5;&#x672C;&#x8EAB;&#x662F;&#x7528;<strong>this</strong>&#x52A0;&#x9501;&#x7684;&#xFF0C;&#x7406;&#x8BBA;&#x4E0A;&#x662F;&#x4E0D;&#x4F1A;&#x51FA;&#x73B0;&#xFF0C;&#x8FDB;&#x4E86;&#x8FD9;&#x4E2A;&#x65B9;&#x6CD5;&#xFF0C;<strong>mLoaded</strong>&#x4E3A;true&#x7684;&#x60C5;&#x51B5;&#x3002;</p>
<h4 id="sharedpreferences">SharedPreferences&#x8BFB;&#x53D6;</h4>
<p>&#x8BFB;&#x53D6;&#x76F8;&#x5173;&#x7684;&#x4EE3;&#x7801;&#x76F8;&#x5BF9;&#x7B80;&#x5355;&#xFF0C;&#x53D6;&#x4E00;&#x6BB5;&#x4F5C;&#x4E3A;&#x6837;&#x4F8B;&#xFF1A;</p>
<script src="https://gist.github.com/shunix/d20d6f8a6be95a49e71a0feae4efe475.js"></script>
<p><strong>awaitLoadedLocked</strong>&#x5728;&#x6BCF;&#x6B21;&#x53D6;&#x6570;&#x636E;&#x4E4B;&#x524D;&#x90FD;&#x4F1A;&#x8C03;&#x7528;&#xFF0C;&#x5982;&#x679C;mLoaded&#x4E3A;false&#xFF0C;&#x8BF4;&#x660E;&#x6CA1;&#x6709;&#x52A0;&#x8F7D;&#x5B8C;&#xFF0C;&#x90A3;&#x4E48;&#x6302;&#x8D77;&#x5F53;&#x524D;&#x7EBF;&#x7A0B;&#xFF0C;&#x7B49;&#x5F85;&#x52A0;&#x8F7D;&#x5B8C;&#x540E;&#x7EDF;&#x4E00;&#x5524;&#x9192;&#x3002;&#x56E0;&#x4E3A;&#x7528;&#x4E86;wait/notify&#xFF0C;&#x6240;&#x4EE5;<strong>awaitLoadedLocked</strong>&#x8C03;&#x7528;&#x524D;&#x5FC5;&#x987B;&#x83B7;&#x53D6;this&#x7684;&#x9501;&#x3002;<br>
&#x53D6;&#x6570;&#x636E;&#x5C31;&#x662F;&#x4ECE;<strong>mMap</strong>&#x4E2D;&#x6839;&#x636E;key&#x53D6;&#x51FA;&#x9700;&#x8981;&#x7684;&#x6570;&#x636E;&#xFF0C;&#x5982;&#x679C;&#x662F;<strong>getAll()<strong>&#x7684;&#x8BDD;&#xFF0C;&#x8FD9;&#x91CC;&#x8FD4;&#x56DE;&#x7684;&#x662F;</strong>mMap</strong>&#x7684;&#x526F;&#x672C;&#xFF0C;&#x4EE5;&#x514D;&#x5BF9;&#x8FD4;&#x56DE;&#x6570;&#x636E;&#x7684;&#x4FEE;&#x6539;&#x5F71;&#x54CD;&#x4E86;<strong>mMap</strong>&#x7684;&#x503C;&#x3002;&#x8FD9;&#x91CC;<strong>mMap</strong>&#x662F;&#x5982;&#x4F55;&#x4FDD;&#x8BC1;&#x548C;&#x78C1;&#x76D8;&#x4E0A;&#x6587;&#x4EF6;&#x540C;&#x6B65;&#x7684;&#xFF0C;&#x770B;&#x5B8C;&#x540E;&#x9762;SharedPreferences&#x7684;&#x5199;&#x5165;&#x5C31;&#x4F1A;&#x660E;&#x767D;&#x3002;</p>
<h4 id="sharedpreferences">SharedPreferences&#x5199;&#x5165;</h4>
<p>SharedPreferences&#x7684;&#x5199;&#x5165;&#x662F;&#x6574;&#x4E2A;SharedPreferences&#x6E90;&#x7801;&#x4E2D;&#x6700;&#x590D;&#x6742;&#x7684;&#x4E00;&#x5757;&#x3002;&#x4F46;&#x53EA;&#x662F;&#x76F8;&#x5BF9;&#x800C;&#x8A00;&#xFF0C;&#x5176;&#x5B9E;&#x4ED4;&#x7EC6;&#x770B;&#x770B;&#x8FD8;&#x662F;&#x5F88;&#x597D;&#x7406;&#x89E3;&#x7684;&#x3002;<br>
SharedPreferences&#x7684;&#x6240;&#x6709;&#x5199;&#x5165;&#x64CD;&#x4F5C;&#xFF0C;&#x90FD;&#x662F;&#x901A;&#x8FC7;&#x4E00;&#x4E2A;&#x5185;&#x90E8;&#x7C7B;<strong>SharedPreferencesImpl.EditorImpl</strong>&#x6765;&#x5B9E;&#x73B0;&#x7684;&#x3002;&#x6E90;&#x7801;&#x91CC;&#x7684;putXX&#x65B9;&#x6CD5;&#x6211;&#x53EA;&#x6458;&#x4E86;&#x4E00;&#x4E2A;&#x51FA;&#x6765;&#xFF0C;&#x591A;&#x4F59;&#x7684;&#x53BB;&#x6389;&#x4E86;&#xFF1A;</p>
<script src="https://gist.github.com/shunix/88b9ae40fb3f5eeedcfd6c4179ea8b8b.js"></script>
<p>&#x6211;&#x4EEC;&#x77E5;&#x9053;&#xFF0C;&#x5199;&#x5165;&#x6D41;&#x7A0B;&#xFF0C;&#x4E00;&#x822C;&#x90FD;&#x662F;putXX-&gt;commit/apply&#xFF0C;&#x6211;&#x4EEC;&#x5C31;&#x6309;&#x8FD9;&#x4E2A;&#x6D41;&#x7A0B;&#x5165;&#x624B;&#xFF0C;&#x6765;&#x770B;&#x770B;&#x5230;&#x5E95;&#x5199;&#x5165;SharedPreferences&#x7684;&#x65F6;&#x5019;&#x6267;&#x884C;&#x4E86;&#x54EA;&#x4E9B;&#x64CD;&#x4F5C;&#x3002;&#x8FD9;&#x91CC;&#x53EF;&#x4EE5;&#x770B;&#x5230;&#xFF0C;putXX&#x5B9E;&#x9645;&#x4E0A;&#x6267;&#x884C;&#x7684;&#x64CD;&#x4F5C;&#xFF0C;&#x5C31;&#x662F;&#x628A;key/value&#x5BF9;&#x653E;&#x5230;&#x4E86;<strong>mModified</strong>&#x91CC;&#x9762;&#x3002;&#x771F;&#x6B63;&#x7684;&#x5199;&#x5165;&#x8FC7;&#x7A0B;&#xFF0C;&#x5148;&#x4EE5;<strong>commit()<strong>&#x65B9;&#x6CD5;&#x4E3A;&#x4F8B;&#x770B;&#x770B;&#x3002;<br>
&#x8FD9;&#x91CC;&#x53C8;&#x8981;&#x5F15;&#x5165;&#x53E6;&#x4E00;&#x4E2A;&#x5185;&#x90E8;&#x7C7B;</strong>MemoryCommitResult</strong></p>
<script src="https://gist.github.com/shunix/79b9fdbd73d7e9ff13827abeb60cc4c7.js"></script>
<p>&#x8FD9;&#x4E2A;&#x5185;&#x90E8;&#x7C7B;&#x8868;&#x793A;&#x7684;&#x662F;&#x628A;&#x4FEE;&#x6539;&#x63D0;&#x4EA4;&#x5230;&#x5185;&#x5B58;&#x7684;&#x7ED3;&#x679C;&#x3002;<strong>commit()<strong>&#x65B9;&#x6CD5;&#x7684;&#x5B9E;&#x73B0;&#xFF0C;&#x5148;&#x8C03;&#x7528;&#x4E86;</strong>commitToMemory()<strong>&#x65B9;&#x6CD5;&#xFF0C;&#x83B7;&#x53D6;&#x4E86;&#x8FD4;&#x56DE;&#x7684;</strong>MemoryCommitResult</strong>&#x4E4B;&#x540E;&#xFF0C;&#x518D;&#x628A;&#x8FD4;&#x56DE;&#x7ED3;&#x679C;&#x52A0;&#x5165;&#x78C1;&#x76D8;&#x5199;&#x5165;&#x961F;&#x5217;&#xFF0C;&#x5E76;&#x5728;&#x5F53;&#x524D;&#x7EBF;&#x7A0B;&#x7B49;&#x5F85;&#x5199;&#x5165;&#x64CD;&#x4F5C;&#x5B8C;&#x6210;&#xFF0C;&#x6700;&#x540E;&#x901A;&#x77E5;&#x6240;&#x6709;&#x7684;&#x76D1;&#x542C;&#x5668;&#xFF0C;&#x5199;&#x5165;&#x5B8C;&#x6210;&#x3002;</p>
<h5 id>&#x63D0;&#x4EA4;&#x5230;&#x5185;&#x5B58;</h5>
<p>**commitToMemory()**&#x7684;&#x5B9E;&#x73B0;&#x6BD4;&#x8F83;&#x7E41;&#x7410;&#xFF0C;&#x8FD9;&#x91CC;&#x5206;&#x6B65;&#x8BB2;&#x89E3;&#x4E00;&#x4E0B;&#xFF1A;</p>
<ol>
<li>&#x5148;&#x68C0;&#x67E5;<strong>mDiskWritesInFlight</strong>&#x53D8;&#x91CF;&#xFF0C;&#x770B;&#x6709;&#x6CA1;&#x6709;&#x6B63;&#x5728;&#x5199;&#x5165;&#xFF0C;&#x6216;&#x8005;&#x7B49;&#x5F85;&#x5199;&#x5165;&#x7684;&#x6570;&#x636E;&#xFF0C;&#x5982;&#x679C;&#x6709;&#x7684;&#x8BDD;&#xFF0C;&#x8FD9;&#x91CC;&#x8981;&#x505A;&#x4E00;&#x6B21;&#x6DF1;&#x62F7;&#x8D1D;&#x3002;&#x8FD9;&#x91CC;&#x7B2C;60&#x884C;&#x6211;&#x521D;&#x770B;&#x4E5F;&#x89C9;&#x5F97;&#x5F88;&#x5947;&#x602A;&#xFF0C;&#x4F46;&#x662F;&#x7ED3;&#x5408;&#x540E;&#x9762;&#x4E00;&#x8D77;&#x770B;&#xFF0C;&#x5C31;&#x80FD;&#x7406;&#x89E3;&#x4E86;&#x3002;&#x8FD9;&#x91CC;&#x6CE8;&#x610F;&#x5230;&#xFF0C;&#x7B2C;62&#x884C;&#x662F;&#x76F4;&#x63A5;&#x628A;<strong>mMap</strong>&#x8D4B;&#x503C;&#x7ED9;&#x4E86;<strong>mapToWriteToDisk</strong>&#xFF0C;&#x8FD9;&#x91CC;&#x662F;&#x6D45;&#x62F7;&#x8D1D;&#xFF0C;&#x4E5F;&#x5C31;&#x662F;&#x8BF4;&#xFF0C;&#x4FEE;&#x6539;<strong>mMap</strong>&#x7684;&#x503C;&#xFF0C;&#x540C;&#x6837;&#x4F1A;&#x5F71;&#x54CD;<strong>mapToWriteToDisk</strong>&#xFF0C;&#x800C;&#x540E;&#x8005;&#x662F;&#x88AB;&#x52A0;&#x5165;&#x78C1;&#x76D8;&#x5199;&#x5165;&#x961F;&#x5217;&#xFF0C;&#x6B63;&#x5728;&#x88AB;&#x5199;&#x5165;&#xFF0C;&#x6216;&#x8005;&#x5C06;&#x8981;&#x88AB;&#x5199;&#x5165;&#x5230;&#x78C1;&#x76D8;&#x7684;Map&#xFF0C;&#x8FD9;&#x79CD;&#x5F71;&#x54CD;&#x663E;&#x7136;&#x662F;&#x6211;&#x4EEC;&#x4E0D;&#x5E0C;&#x671B;&#x53D1;&#x751F;&#x7684;&#xFF0C;&#x56E0;&#x4E3A;&#x5728;&#x5199;&#x5165;&#x78C1;&#x76D8;&#x65F6;&#xFF0C;&#x83B7;&#x53D6;&#x7684;&#x9501;&#x5E76;&#x4E0D;&#x662F;<strong>this</strong>&#xFF0C;&#x5982;&#x679C;<strong>mapToWriteToDisk</strong>&#x5728;&#x8FD9;&#x65F6;&#x88AB;&#x4FEE;&#x6539;&#xFF0C;&#x53EF;&#x80FD;&#x51FA;&#x73B0;&#x5F02;&#x5E38;&#x3002;&#x6240;&#x4EE5;&#x8FD9;&#x91CC;&#x6DF1;&#x62F7;&#x8D1D;&#x4E4B;&#x540E;&#xFF0C;&#x53EF;&#x4EE5;&#x4FDD;&#x8BC1;<strong>mapToWriteToDisk</strong>&#x6307;&#x5411;&#x7684;&#xFF0C;&#x6C38;&#x8FDC;&#x662F;&#x90A3;&#x4E2A;&#x65F6;&#x523B;&#x7684;Map&#x3002;</li>
<li>&#x589E;&#x52A0;<strong>mDiskWritesInFlight</strong>&#xFF0C;&#x6807;&#x8BB0;&#x8981;&#x5199;&#x5165;&#x78C1;&#x76D8;&#x7684;&#x4EFB;&#x52A1;&#x589E;&#x52A0;&#x4E86;&#x4E00;&#x4E2A;&#x3002;</li>
<li>&#x68C0;&#x67E5;<strong>mClear</strong>&#xFF0C;&#x770B;&#x770B;&#x662F;&#x5426;&#x9700;&#x8981;&#x6E05;&#x7A7A;&#x5F53;&#x524D;SharedPreferences&#x3002;</li>
<li>81-106&#x884C;&#x5408;&#x5E76;&#x4E86;<strong>mModified</strong>&#x5230;<strong>mMap</strong>&#xFF0C;&#x8FD9;&#x91CC;&#x9700;&#x8981;&#x6CE8;&#x610F;&#x4E00;&#x4E2A;&#x5F88;tricky&#x7684;&#x5730;&#x65B9;&#xFF0C;&#x7B2C;87&#x884C;&#x7684;&#x5224;&#x65AD;&#xFF0C;&#x5176;&#x5B9E;<strong>remove()<strong>&#x65B9;&#x6CD5;&#x7684;&#x5B9E;&#x73B0;&#xFF0C;&#x5C31;&#x662F;&#x628A;value&#x8BBE;&#x4E3A;</strong>EditorImpl</strong>&#x672C;&#x8EAB;&#xFF0C;&#x6548;&#x679C;&#x7B49;&#x540C;&#x4E8E;&#x628A;&#x67D0;&#x4E00;&#x4E2A;key&#x5BF9;&#x5E94;&#x7684;value&#x8BBE;&#x4E3A;null&#x3002;</li>
<li>&#x6700;&#x540E;&#x628A;<strong>mModified</strong>&#x6E05;&#x7A7A;&#xFF0C;&#x56E0;&#x4E3A;&#x5DF2;&#x7ECF;&#x88AB;&#x5408;&#x5E76;&#x5230;&#x4E86;<strong>mMap</strong>&#x3002;</li>
</ol>
<h5 id>&#x5199;&#x5165;&#x78C1;&#x76D8;</h5>
<p>&#x5199;&#x5165;&#x78C1;&#x76D8;&#x76F8;&#x5173;&#x7684;&#x4EE3;&#x7801;&#x5982;&#x4E0B;&#xFF1A;</p>
<script src="https://gist.github.com/shunix/ae51b74893c35dfa454535dbb4401997.js"></script>
<p><strong>enqueueDiskWrite</strong>&#x65B9;&#x6CD5;&#x63A5;&#x6536;&#x4E24;&#x4E2A;&#x53C2;&#x6570;&#xFF0C;&#x7B2C;&#x4E00;&#x4E2A;&#x662F;&#x4E0A;&#x4E00;&#x6B65;&#x8FD4;&#x56DE;&#x7684;<strong>MemoryCommitResult</strong>&#x5BF9;&#x8C61;&#xFF0C;&#x7B2C;&#x4E8C;&#x4E2A;&#x53C2;&#x6570;&#x662F;&#x4E00;&#x4E2A;<strong>Runnable</strong>&#x5BF9;&#x8C61;&#xFF0C;&#x5982;&#x679C;&#x662F;&#x4ECE;<strong>commit()<strong>&#x8C03;&#x7528;&#x7684;&#xFF0C;&#x7B2C;&#x4E8C;&#x4E2A;&#x53C2;&#x6570;&#x5E94;&#x8BE5;&#x4E3A;&#x7A7A;&#x3002;&#x8FD9;&#x91CC;&#x7684;</strong>QueuedWork</strong>&#x662F;&#x4E00;&#x4E2A;&#x5DE5;&#x5177;&#x7C7B;&#xFF0C;&#x4F1A;&#x521B;&#x5EFA;&#x4E00;&#x4E2A;&#x5F53;&#x524D;&#x8FDB;&#x7A0B;&#x5171;&#x4EAB;&#x7684;&#x5355;&#x7EBF;&#x7A0B;&#x6267;&#x884C;&#x5668;&#xFF0C;&#x5176;&#x5B9E;&#x76F8;&#x5F53;&#x4E8E;&#x4E00;&#x4E2A;&#x961F;&#x5217;&#xFF0C;&#x6309;&#x7167;&#x5165;&#x961F;&#x5217;&#x987A;&#x5E8F;&#x6267;&#x884C;&#x5199;&#x5165;&#x64CD;&#x4F5C;&#x3002;&#x6CE8;&#x610F;&#xFF0C;&#x5982;&#x679C;&#x662F;<strong>commit()<strong>&#x8C03;&#x7528;&#xFF0C;&#x8FD9;&#x91CC;&#x5E76;&#x4E0D;&#x4F1A;&#x7528;&#x5230;</strong>QueuedWork</strong>&#x7684;&#x7EBF;&#x7A0B;&#x6C60;&#xFF0C;&#x800C;&#x662F;&#x76F4;&#x63A5;&#x5728;&#x5F53;&#x524D;&#x7EBF;&#x7A0B;&#x5B8C;&#x6210;&#x5199;&#x8BCD;&#x76D8;&#x64CD;&#x4F5C;&#x3002;&#x5199;&#x5165;&#x64CD;&#x4F5C;&#x7684;&#x5177;&#x4F53;&#x5B9E;&#x73B0;&#x5728;<strong>writeToFile</strong>&#x65B9;&#x6CD5;&#x3002;</p>
<ol>
<li>&#x7B2C;77&#x5230;96&#x884C;&#xFF0C;&#x91CD;&#x547D;&#x540D;&#x5F53;&#x524D;&#x6587;&#x4EF6;&#x4F5C;&#x4E3A;&#x5907;&#x4EFD;&#x6587;&#x4EF6;&#xFF0C;&#x7528;&#x4E8E;&#x5728;&#x5199;&#x5165;&#x9519;&#x8BEF;&#x7684;&#x65F6;&#x5019;&#x8FDB;&#x884C;&#x56DE;&#x6EDA;&#x3002;&#x5982;&#x679C;&#x5907;&#x4EFD;&#x6587;&#x4EF6;&#x5DF2;&#x7ECF;&#x5B58;&#x5728;&#xFF0C;&#x90A3;&#x4E48;&#x8BF4;&#x660E;&#x5F53;&#x524D;&#x6587;&#x4EF6;&#x662F;&#x6709;&#x95EE;&#x9898;&#x7684;&#xFF0C;&#x76F4;&#x63A5;&#x5220;&#x9664;&#x5F53;&#x524D;&#x6587;&#x4EF6;&#x3002;</li>
<li>&#x628A;<strong>MemoryCommitResult.mapToWriteToDisk</strong>&#x5199;&#x5165;&#x5230;&#x78C1;&#x76D8;&#xFF0C;&#x5E76;&#x6267;&#x884C;fsync&#x64CD;&#x4F5C;&#xFF0C;&#x7136;&#x540E;&#x6839;&#x636E;<strong>mMode</strong>&#x8BBE;&#x7F6E;&#x6587;&#x4EF6;&#x6743;&#x9650;&#x3002;</li>
<li>&#x8BB0;&#x5F55;&#x4E0B;&#x5F53;&#x524D;&#x6587;&#x4EF6;&#x7684;&#x5927;&#x5C0F;&#x548C;&#x4FEE;&#x6539;&#x65F6;&#x95F4;&#x6233;&#x5230;<strong>mStatSize</strong>&#x548C;<strong>mStatTimestamp</strong>&#x3002;</li>
<li>&#x5220;&#x9664;&#x5907;&#x4EFD;&#x6587;&#x4EF6;&#xFF0C;&#x5E76;&#x8FD4;&#x56DE;&#x7ED3;&#x679C;&#x7ED9;<strong>MemoryCommitResult</strong>&#xFF0C;&#x8FD9;&#x4E2A;&#x64CD;&#x4F5C;&#x4F1A;&#x89E3;&#x9664;<strong>commit()<strong>&#x5BF9;</strong>CountDownLatch</strong>&#x7684;&#x7B49;&#x5F85;&#x3002;</li>
<li>&#x5982;&#x679C;&#x4E0A;&#x8FF0;&#x64CD;&#x4F5C;&#x5931;&#x8D25;&#xFF0C;&#x5219;&#x5220;&#x9664;&#x672A;&#x5B8C;&#x6210;&#x5199;&#x5165;&#x7684;&#x6587;&#x4EF6;&#x3002;</li>
</ol>
<h5 id>&#x5F02;&#x6B65;&#x5199;&#x5165;</h5>
<p>&#x73B0;&#x5728;&#x518D;&#x6765;&#x770B;&#x770B;**apply()**&#x65B9;&#x6CD5;&#x7684;&#x5B9E;&#x73B0;&#xFF1A;</p>
<script src="https://gist.github.com/shunix/3c098d5236fe181bfabc9e8d0fd3e658.js"></script>
<p>&#x628A;<strong>apply()<strong>&#x548C;</strong>commit()<strong>&#x7ED3;&#x5408;&#x8D77;&#x6765;&#x770B;&#xFF0C;<strong>commit()<strong>&#x76F4;&#x63A5;&#x5728;&#x5F53;&#x524D;&#x7EBF;&#x7A0B;&#x6267;&#x884C;&#x4E86;await&#x64CD;&#x4F5C;&#xFF0C;&#x800C;</strong>apply()<strong>&#x662F;&#x5199;&#x4E86;&#x4E00;&#x4E2A;</strong>Runnable</strong>&#xFF0C;&#x8FD9;&#x4E2A;</strong>awaitCommit</strong>&#x6700;&#x540E;&#x4F1A;&#x5728;&#x54EA;&#x4E2A;&#x7EBF;&#x7A0B;&#x6267;&#x884C;&#x5462;&#xFF1F;&#x8FD9;&#x91CC;&#x5C31;&#x8981;&#x770B;&#x770B;<strong>QueuedWork</strong>&#x7684;&#x6E90;&#x7801;&#xFF1A;</p>
<script src="https://gist.github.com/shunix/0625fbb8603a29112caf644c4c125041.js"></script>
<p>&#x4ECE;&#x4EE3;&#x7801;&#x91CC;&#x53EF;&#x4EE5;&#x770B;&#x5230;&#xFF0C;&#x8FD9;&#x91CC;&#x628A;<strong>awaitCommit</strong>&#x52A0;&#x5165;&#x5230;<strong>QueuedWork.sPendingWorkFinishers</strong>&#xFF0C;&#x5E76;&#x4E0D;&#x4F1A;&#x9A6C;&#x4E0A;&#x6267;&#x884C;&#xFF0C;&#x53EA;&#x4F1A;&#x5728;<strong>waitToFinish()<strong>&#x4E2D;&#x6267;&#x884C;&#xFF0C;&#x800C;&#x8FD9;&#x4E2A;&#x65B9;&#x6CD5;&#x7684;&#x8C03;&#x7528;&#x65F6;&#x673A;&#xFF0C;&#x4E5F;&#x53EA;&#x6709;Activity&#x7684;onPause()&#x4E2D;&#xFF0C;BroadcastReceiver&#x7684;onReceive()&#x8C03;&#x7528;&#x540E;&#x7B49;&#x51E0;&#x4E2A;&#x65F6;&#x673A;&#xFF0C;&#x53EA;&#x662F;&#x4E3A;&#x4E86;&#x4FDD;&#x8BC1;&#x5F02;&#x6B65;&#x4EFB;&#x52A1;&#x4E0D;&#x4E22;&#x5931;&#x800C;&#x505A;&#x7684;fallback&#x903B;&#x8F91;&#x3002;&#x771F;&#x6B63;&#x7684;&#x5199;&#x5165;&#x8FD8;&#x662F;&#x8C03;&#x7528;</strong>writeToFile()<strong>&#x65B9;&#x6CD5;&#xFF0C;&#x4EFB;&#x52A1;&#x4F1A;&#x88AB;&#x5206;&#x53D1;&#x7ED9;</strong>QueuedWork</strong>&#x63D0;&#x4F9B;&#x7684;&#x5355;&#x7EBF;&#x7A0B;&#x7EBF;&#x7A0B;&#x6C60;&#x6267;&#x884C;&#x3002;</p>
<h4 id>&#x591A;&#x8FDB;&#x7A0B;&#x95EE;&#x9898;</h4>
<p>&#x6700;&#x540E;&#x6765;&#x8BF4;&#x4E00;&#x4E0B;<strong>SharedPreferences</strong>&#x7684;&#x4E00;&#x4E2A;&#x6700;&#x5927;&#x7684;&#x5751;&#xFF0C;&#x591A;&#x8FDB;&#x7A0B;&#x4E0B;&#x7684;&#x95EE;&#x9898;&#x3002;&#x5148;&#x6765;&#x770B;&#x4E00;&#x4E2A;flag&#x7684;&#x5B9A;&#x4E49;&#xFF1A;</p>
<blockquote>
<p>Context.MODE_MULTI_PROCESS<br>
This constant was deprecated in API level 23. MODE_MULTI_PROCESS does not work reliably in some versions of Android, and furthermore does not provide any mechanism for reconciling concurrent modifications across processes. Applications should not attempt to use it. Instead, they should use an explicit cross-process data management approach such as ContentProvider.</p>
</blockquote>
<p>&#x770B;&#x5B98;&#x65B9;&#x6587;&#x6863;&#xFF0C;&#x4ED6;&#x4EEC;&#x8FD8;&#x662F;&#x77E5;&#x9053;&#x8FD9;&#x91CC;&#x7684;&#x5B9E;&#x73B0;&#x662F;&#x6709;&#x95EE;&#x9898;&#x7684;&#x3002;&#x6211;&#x4EEC;&#x56DE;&#x6EAF;&#x5230;&#x4EE3;&#x7801;&#xFF0C;&#x770B;&#x4E00;&#x4E0B;&#x5BF9;&#x4E8E;&#x8FD9;&#x4E2A;flag&#x7684;&#x5904;&#x7406;&#xFF0C;&#x524D;&#x9762;&#x6211;&#x4EEC;&#x770B;&#x5230;&#x8FC7;&#xFF0C;<strong>ContextImpl</strong>&#x5982;&#x679C;&#x53D1;&#x73B0;&#x4E86;&#x8FD9;&#x4E2A;flag&#xFF0C;&#x5C31;&#x4F1A;&#x8C03;&#x7528;**SharedPreferencesImpl.startReloadIfChangedUnexpectedly()**&#x65B9;&#x6CD5;&#xFF0C;&#x8FD9;&#x4E2A;&#x65B9;&#x6CD5;&#x5B9E;&#x73B0;&#x5982;&#x4E0B;&#xFF1A;</p>
<script src="https://gist.github.com/shunix/a60dc821d9e710c5594744c56d856d6a.js"></script>
<p>&#x8FD9;&#x4E2A;&#x65B9;&#x6CD5;&#x505A;&#x7684;&#xFF0C;&#x4EC5;&#x4EC5;&#x662F;&#x5728;&#x6587;&#x4EF6;&#x6709;&#x53D8;&#x5316;&#x7684;&#x65F6;&#x5019;&#xFF0C;&#x91CD;&#x65B0;&#x52A0;&#x8F7D;&#x4E86;&#x4E00;&#x904D;&#x3002;&#x9996;&#x5148;&#xFF0C;&#x8FD9;&#x4E2A;&#x64CD;&#x4F5C;&#x4E0D;&#x662F;&#x539F;&#x5B50;&#x6027;&#x7684;&#xFF0C;&#x5E76;&#x6CA1;&#x6709;&#x7528;flock&#x9501;&#x4F4F;&#x6587;&#x4EF6;&#xFF0C;&#x56E0;&#x4E3A;<strong>mFile</strong>&#x548C;<strong>mBackupFile</strong>&#x7684;&#x5173;&#x7CFB;&#xFF0C;&#x4E00;&#x4E2A;&#x8FDB;&#x7A0B;&#x5728;&#x5199;&#xFF0C;&#x800C;&#x53E6;&#x4E00;&#x4E2A;&#x8FDB;&#x7A0B;&#x5728;&#x8BFB;&#x7684;&#x65F6;&#x5019;&#xFF0C;&#x5C31;&#x4F1A;&#x9020;&#x6210;&#x5199;&#x5165;&#x7684;&#x6570;&#x636E;&#x4E22;&#x5931;&#x3002;&#x7B2C;&#x4E8C;&#xFF0C;&#x8FD9;&#x4E2A;&#x5224;&#x65AD;&#x6587;&#x4EF6;&#x662F;&#x5426;&#x6709;&#x53D8;&#x5316;&#x7684;&#x6761;&#x4EF6;&#x4E5F;&#x662F;&#x6709;&#x95EE;&#x9898;&#x7684;&#xFF0C;&#x53EA;&#x8981;&#x68C0;&#x6D4B;&#x5230;<strong>mDiskWritesInFlight</strong>&#x5927;&#x4E8E;0&#x5C31;&#x8BA4;&#x4E3A;&#x662F;&#x81EA;&#x5DF1;&#x4FEE;&#x6539;&#x4E86;&#x6587;&#x4EF6;&#x65F6;&#x95F4;&#x6233;&#xFF0C;&#x8FD9;&#x662F;&#x4E0D;&#x4E25;&#x8C28;&#x7684;&#xFF0C;&#x5047;&#x5982;&#x5F53;&#x524D;&#x8FDB;&#x7A0B;&#x7684;&#x5199;&#x4EFB;&#x52A1;&#x53EA;&#x662F;&#x521A;&#x521A;&#x5199;&#x5230;&#x4E86;&#x5185;&#x5B58;&#xFF0C;&#x800C;&#x53E6;&#x4E00;&#x4E2A;&#x8FDB;&#x7A0B;&#x4FEE;&#x6539;&#x4E86;&#x6587;&#x4EF6;&#xFF0C;&#x6B64;&#x65F6;<strong>mDiskWritesInFlight</strong>&#x662F;&#x5927;&#x4E8E;0&#x7684;&#xFF0C;&#x4F46;&#x662F;&#x6587;&#x4EF6;&#x786E;&#x5B9E;&#x53D1;&#x751F;&#x4E86;&#x672C;&#x8FDB;&#x7A0B;&#x4E0D;&#x77E5;&#x9053;&#x7684;&#x4FEE;&#x6539;&#xFF0C;&#x53E6;&#x4E00;&#x4E2A;&#x8FDB;&#x7A0B;&#x5199;&#x5165;&#x7684;&#x6570;&#x636E;&#x8FD8;&#x662F;&#x8BFB;&#x4E0D;&#x5230;&#x3002;&#x6240;&#x4EE5;&#x5B98;&#x65B9;&#x5F88;&#x826F;&#x5FC3;&#x5730;&#x5E9F;&#x5F03;&#x4E86;&#x8FD9;&#x4E2A;Flag&#xFF0C;&#x8F6C;&#x800C;&#x63A8;&#x8350;&#x7528;ContentProvider&#x5B9E;&#x73B0;&#x8DE8;&#x8FDB;&#x7A0B;&#x6570;&#x636E;&#x5171;&#x4EAB;&#x3002;</p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[TLS握手过程]]></title><description><![CDATA[<!--kg-card-begin: markdown--><p>&#x6700;&#x8FD1;&#x548C;&#x670B;&#x53CB;&#x5403;&#x996D;&#x7684;&#x65F6;&#x5019;&#xFF0C;&#x804A;&#x5230;&#x4E86;HTTPS&#xFF0C;HTTPS&#x5176;&#x5B9E;&#x5C31;&#x662F;&#x57FA;&#x4E8E;TLS&#x5EFA;&#x7ACB;&#x4E86;&#x5B89;&#x5168;&#x4FE1;&#x9053;&#x7684;HTTP&#x534F;&#x8BAE;&#x3002;&#x6240;&#x4EE5;&#x53EF;&#x4EE5;&#x8BF4;&#xFF0C;HTTPS&#x6700;&#x91CD;&#x8981;&#x7684;&#x5C31;&#x662F;TLS&</p>]]></description><link>https://shunix.com/tls-handshake/</link><guid isPermaLink="false">60812ae62b3f873b19511ebe</guid><category><![CDATA[技术文章]]></category><dc:creator><![CDATA[Shunix]]></dc:creator><pubDate>Wed, 13 Sep 2017 13:30:23 GMT</pubDate><content:encoded><![CDATA[<!--kg-card-begin: markdown--><p>&#x6700;&#x8FD1;&#x548C;&#x670B;&#x53CB;&#x5403;&#x996D;&#x7684;&#x65F6;&#x5019;&#xFF0C;&#x804A;&#x5230;&#x4E86;HTTPS&#xFF0C;HTTPS&#x5176;&#x5B9E;&#x5C31;&#x662F;&#x57FA;&#x4E8E;TLS&#x5EFA;&#x7ACB;&#x4E86;&#x5B89;&#x5168;&#x4FE1;&#x9053;&#x7684;HTTP&#x534F;&#x8BAE;&#x3002;&#x6240;&#x4EE5;&#x53EF;&#x4EE5;&#x8BF4;&#xFF0C;HTTPS&#x6700;&#x91CD;&#x8981;&#x7684;&#x5C31;&#x662F;TLS&#x7684;&#x63E1;&#x624B;&#x8FC7;&#x7A0B;&#x3002;&#x8FD9;&#x7BC7;post&#x6574;&#x7406;&#x4E86;&#x4E00;&#x4E0B;TLS&#x7684;&#x63E1;&#x624B;&#x8FC7;&#x7A0B;&#x3002;</p>
<h4 id>&#x524D;&#x7F6E;&#x77E5;&#x8BC6;</h4>
<p>&#x8FD9;&#x91CC;&#x8981;&#x5148;&#x8BB2;&#x51E0;&#x4E2A;&#x6982;&#x5FF5;&#xFF0C;&#x5728;&#x540E;&#x9762;&#x5BF9;&#x4E8E;TLS&#x63E1;&#x624B;&#x8FC7;&#x7A0B;&#x7684;&#x63CF;&#x8FF0;&#x4E2D;&#x4F1A;&#x7528;&#x5230;&#x8FD9;&#x51E0;&#x4E2A;&#x6982;&#x5FF5;&#x3002;</p>
<h5 id="httpstlsssl">HTTPS TLS&#x548C;SSL&#x7684;&#x5173;&#x7CFB;</h5>
<p>SSL&#x662F;90&#x5E74;&#x4EE3;Netscape&#x5F04;&#x51FA;&#x6765;&#x7684;&#x4E00;&#x5957;&#x4E1C;&#x897F;&#xFF0C;&#x4E3A;&#x7684;&#x662F;&#x89E3;&#x51B3;HTTP&#x534F;&#x8BAE;&#x660E;&#x6587;&#x4F20;&#x8F93;&#x6570;&#x636E;&#x7684;&#x95EE;&#x9898;&#x3002;&#x540E;&#x6765;SSL&#x6162;&#x6162;&#x6210;&#x4E86;&#x4E8B;&#x5B9E;&#x4E0A;&#x7684;&#x6807;&#x51C6;&#xFF0C;&#x4E8E;&#x662F;IETF&#x5C31;&#x628A;SSL&#x6807;&#x51C6;&#x5316;&#x4E86;&#xFF0C;&#x540D;&#x5B57;&#x53EB;&#x505A;TLS&#xFF0C;TLS 1.0&#x5176;&#x5B9E;&#x5C31;&#x662F;SSL 3.1&#x3002;&#x6240;&#x4EE5;SSL&#x548C;TLS&#x7ECF;&#x5E38;&#x88AB;&#x653E;&#x5728;&#x4E00;&#x8D77;&#x5199;&#x6210;SSL/TLS&#xFF0C;&#x56E0;&#x4E3A;&#x8FD9;&#x4E24;&#x4E2A;&#x540D;&#x8BCD;&#x5728;&#x73B0;&#x5728;&#x5176;&#x5B9E;&#x5C31;&#x662F;&#x540C;&#x4E00;&#x4E2A;&#x4E1C;&#x897F;&#x3002;HTTPS&#x662F;&#x4F7F;&#x7528;TLS&#x7684;HTTP&#x534F;&#x8BAE;&#x3002;</p>
<h5 id>&#x8BC1;&#x4E66;&#x53CA;&#x4FE1;&#x4EFB;&#x94FE;</h5>
<p>&#x6211;&#x4EEC;&#x77E5;&#x9053;&#xFF0C;HTTPS&#x7684;&#x7F51;&#x7AD9;&#x90FD;&#x6709;&#x4E00;&#x4E2A;&#x81EA;&#x5DF1;&#x7684;&#x8BC1;&#x4E66;&#xFF0C;&#x7528;&#x4E8E;&#x8868;&#x660E;&#x81EA;&#x5DF1;&#x7684;&#x8EAB;&#x4EFD;&#x3002;&#x8BC1;&#x4E66;&#x672C;&#x8D28;&#x4E0A;&#x662F;&#x4E3A;&#x4E86;&#x8BA9;&#x516C;&#x94A5;&#x80FD;&#x53EF;&#x4FE1;&#x7684;&#x4F20;&#x8F93;&#x3002;&#x516C;&#x94A5;&#x662F;&#x653E;&#x5728;&#x8BC1;&#x4E66;&#x91CC;&#x9762;&#x7684;&#xFF0C;&#x5982;&#x679C;&#x8BC1;&#x4E66;&#x53EF;&#x4FE1;&#xFF0C;&#x90A3;&#x4E48;&#x516C;&#x94A5;&#x5C31;&#x4E5F;&#x662F;&#x53EF;&#x4FE1;&#x7684;&#x3002;&#x90A3;&#x4E3A;&#x4EC0;&#x4E48;&#x4E00;&#x4E2A;&#x516C;&#x94A5;&#x662F;&#x53EF;&#x4FE1;&#x7684;&#x5462;&#xFF1F;&#x8FD9;&#x5C31;&#x8981;&#x8BF4;&#x5230;&#x4FE1;&#x4EFB;&#x94FE;&#x548C;CA&#x3002;CA&#x6307;&#x7684;&#x662F;Certificate Authority&#xFF0C;CA&#x90FD;&#x662F;&#x6743;&#x5A01;&#x673A;&#x6784;&#xFF0C;&#x4ED6;&#x4EEC;&#x7684;&#x8BC1;&#x4E66;&#x53EB;&#x505A;&#x6839;&#x8BC1;&#x4E66;&#xFF0C;&#x8FD9;&#x4E9B;&#x6839;&#x8BC1;&#x4E66;&#x88AB;&#x64CD;&#x4F5C;&#x7CFB;&#x7EDF;&#x4FE1;&#x4EFB;&#xFF0C;&#x6839;&#x8BC1;&#x4E66;&#x4FE1;&#x4EFB;&#x7684;&#x8BC1;&#x4E66;&#x4E5F;&#x662F;&#x53EF;&#x4FE1;&#x7684;&#x3002;&#x56E0;&#x6B64;&#x6743;&#x5A01;&#x673A;&#x6784;&#x9881;&#x53D1;&#x7684;&#x8BC1;&#x4E66;&#x90FD;&#x80FD;&#x88AB;&#x64CD;&#x4F5C;&#x7CFB;&#x7EDF;&#x4FE1;&#x4EFB;&#xFF0C;&#x8FD9;&#x5C31;&#x7EC4;&#x6210;&#x4E86;&#x4FE1;&#x4EFB;&#x94FE;&#x3002;</p>
<h4 id="tls">TLS&#x63E1;&#x624B;&#x8FC7;&#x7A0B;</h4>
<p>&#x8FD9;&#x91CC;&#x501F;&#x7528;&#x4E86;&#x4E00;&#x5F20;CloudFlare&#x7684;&#x56FE;&#xFF0C;&#x8FD9;&#x5F20;&#x56FE;&#x4E0D;&#x662F;&#x5F88;&#x8BE6;&#x7EC6;&#xFF0C;&#x4F46;&#x6211;&#x4E2A;&#x4EBA;&#x89C9;&#x5F97;&#x8FD9;&#x4E2A;&#x7C92;&#x5EA6;&#x5E94;&#x8BE5;&#x662F;&#x6700;&#x5408;&#x9002;&#x7684;&#xFF0C;&#x4E3B;&#x8981;&#x90E8;&#x5206;&#x90FD;&#x6709;&#x63CF;&#x8FF0;&#xFF0C;&#x53C8;&#x4E0D;&#x81F3;&#x4E8E;&#x8BA9;&#x4EBA;&#x8FC7;&#x4E8E;&#x7EA0;&#x7ED3;&#x7EC6;&#x8282;&#x3002;<br>
<img src="https://raw.githubusercontent.com/shunix/BlogImages/master/20170913_ssl_handshake_rsa.jpg" alt="SSL handshake" loading="lazy"><br>
&#x5176;&#x5B9E;TLS&#x63D0;&#x4F9B;&#x4E86;&#x591A;&#x79CD;&#x5BC6;&#x94A5;&#x4EA4;&#x6362;&#x7B97;&#x6CD5;&#xFF0C;&#x8FD9;&#x91CC;&#x4EE5;RSA&#x4E3A;&#x4F8B;&#xFF0C;&#x5206;&#x6B65;&#x8BB2;&#x89E3;&#x4EE5;&#x4E0B;TLS&#x7684;&#x63E1;&#x624B;&#x8FC7;&#x7A0B;&#x3002;</p>
<h5 id>&#x5BA2;&#x6237;&#x7AEF;&#x521D;&#x59CB;&#x8BF7;&#x6C42;</h5>
<p>&#x5BA2;&#x6237;&#x7AEF;&#x5411;&#x670D;&#x52A1;&#x5668;&#x53D1;&#x51FA;&#x8BF7;&#x6C42;&#xFF0C;&#x4F1A;&#x5E26;&#x4E0A;&#x4EE5;&#x4E0B;&#x4FE1;&#x606F;&#xFF1A;</p>
<ol>
<li>&#x4E00;&#x4E2A;&#x5BA2;&#x6237;&#x7AEF;&#x751F;&#x6210;&#x7684;&#x968F;&#x673A;&#x6570;</li>
<li>&#x652F;&#x6301;&#x7684;&#x52A0;&#x5BC6;&#x65B9;&#x5F0F;&#xFF0C;&#x5373;&#x56FE;&#x4E2D;&#x7684;Cipher Suite</li>
<li>&#x652F;&#x6301;SSL/TLS&#x534F;&#x8BAE;&#x7684;&#x7248;&#x672C;&#x53F7;</li>
<li>Session ID&#xFF0C;&#x5982;&#x679C;&#x662F;&#x4E4B;&#x524D;&#x65AD;&#x5F00;&#x7684;&#x4F1A;&#x8BDD;&#xFF0C;&#x4F1A;&#x5E26;&#x4E0A;Session ID&#x7528;&#x6765;&#x6062;&#x590D;&#x4F1A;&#x8BDD;&#x3002;</li>
<li>&#x7B7E;&#x540D;&#x4F7F;&#x7528;&#x7684;&#x54C8;&#x5E0C;&#x7B97;&#x6CD5;</li>
</ol>
<h5 id>&#x670D;&#x52A1;&#x5668;&#x56DE;&#x5E94;</h5>
<p>&#x670D;&#x52A1;&#x5668;&#x54CD;&#x5E94;&#x5BA2;&#x6237;&#x7AEF;&#x7684;&#x8BF7;&#x6C42;&#xFF0C;&#x5982;&#x679C;&#x4E0A;&#x4E00;&#x6B65;&#x5E26;&#x4E0A;&#x4E86;Session ID&#xFF0C;&#x5219;&#x76F4;&#x63A5;&#x6062;&#x590D;&#x4F1A;&#x8BDD;&#xFF0C;&#x5426;&#x5219;&#x5E26;&#x4E0A;&#x4EE5;&#x4E0B;&#x4FE1;&#x606F;&#x7ED9;&#x5BA2;&#x6237;&#x7AEF;&#xFF1A;</p>
<ol>
<li>&#x9009;&#x62E9;SSL/TLS&#x534F;&#x8BAE;&#x7248;&#x672C;&#x53F7;</li>
<li>&#x9009;&#x62E9;&#x52A0;&#x5BC6;&#x65B9;&#x5F0F;</li>
<li>&#x4E00;&#x4E2A;&#x670D;&#x52A1;&#x5668;&#x751F;&#x6210;&#x7684;&#x968F;&#x673A;&#x6570;</li>
<li>&#x670D;&#x52A1;&#x5668;&#x8BC1;&#x4E66;</li>
</ol>
<p>&#x5BA2;&#x6237;&#x7AEF;&#x4F1A;&#x5728;&#x8FD9;&#x91CC;&#x6821;&#x9A8C;&#x670D;&#x52A1;&#x5668;&#x8BC1;&#x4E66;&#x7684;&#x5408;&#x6CD5;&#x6027;&#xFF0C;&#x5305;&#x62EC;&#x68C0;&#x6D4B;&#x8BC1;&#x4E66;&#x6709;&#x6548;&#x65F6;&#x95F4;&#xFF0C;&#x4EE5;&#x53CA;&#x8BC1;&#x4E66;&#x4E2D;&#x57DF;&#x540D;&#x4E0E;&#x5F53;&#x524D;&#x4F1A;&#x8BDD;&#x57DF;&#x540D;&#x662F;&#x5426;&#x5339;&#x914D;&#xFF0C;&#x5E76;&#x6CBF;&#x7740;&#x4FE1;&#x4EFB;&#x94FE;&#x67E5;&#x627E;&#x9876;&#x5C42;&#x8BC1;&#x4E66;&#x9881;&#x53D1;&#x8005;&#x662F;&#x5426;&#x662F;&#x64CD;&#x4F5C;&#x7CFB;&#x7EDF;&#x4FE1;&#x4EFB;&#x7684;CA&#x673A;&#x6784;&#xFF0C;&#x8FD9;&#x91CC;&#x9A8C;&#x8BC1;&#x4FE1;&#x4EFB;&#x94FE;&#x7684;&#x65F6;&#x5019;&#xFF0C;&#x9700;&#x8981;&#x7528;&#x4E0A;&#x4E00;&#x7EA7;&#x8BC1;&#x4E66;&#x7684;&#x516C;&#x94A5;&#x5BF9;&#x8BC1;&#x4E66;&#x91CC;&#x7684;&#x7B7E;&#x540D;&#x8FDB;&#x884C;&#x89E3;&#x5BC6;&#xFF0C;&#x8FD8;&#x539F;&#x5BF9;&#x5E94;&#x7684;&#x6458;&#x8981;&#x503C;&#xFF0C;&#x518D;&#x4F7F;&#x7528;&#x8BC1;&#x4E66;&#x4FE1;&#x606F;&#x8BA1;&#x7B97;&#x8BC1;&#x4E66;&#x7684;&#x6458;&#x8981;&#x503C;&#xFF0C;&#x6700;&#x540E;&#x901A;&#x8FC7;&#x5BF9;&#x6BD4;&#x4E24;&#x4E2A;&#x6458;&#x8981;&#x503C;&#x662F;&#x5426;&#x76F8;&#x7B49;&#xFF0C;&#x5982;&#x679C;&#x4E0D;&#x76F8;&#x7B49;&#x5219;&#x8BA4;&#x4E3A;&#x8BE5;&#x8BC1;&#x4E66;&#x4E0D;&#x53EF;&#x4FE1;&#xFF0C;&#x5982;&#x679C;&#x76F8;&#x7B49;&#x5219;&#x8BA4;&#x4E3A;&#x8BE5;&#x7EA7;&#x8BC1;&#x4E66;&#x94FE;&#x6B63;&#x786E;&#xFF0C;&#x4EE5;&#x6B64;&#x7C7B;&#x63A8;&#x5BF9;&#x6574;&#x4E2A;&#x8BC1;&#x4E66;&#x94FE;&#x8FDB;&#x884C;&#x6821;&#x9A8C;&#x3002;</p>
<h5 id>&#x5BA2;&#x6237;&#x7AEF;&#x56DE;&#x5E94;</h5>
<p>&#x5BA2;&#x6237;&#x7AEF;&#x6821;&#x9A8C;&#x670D;&#x52A1;&#x5668;&#x8BC1;&#x4E66;&#x7684;&#x5408;&#x6CD5;&#x6027;&#xFF0C;&#x751F;&#x6210;premaster secret&#xFF0C;&#x5411;&#x670D;&#x52A1;&#x5668;&#x53D1;&#x9001;&#x4EE5;&#x4E0B;&#x4FE1;&#x606F;&#xFF1A;</p>
<ol>
<li>&#x7528;&#x670D;&#x52A1;&#x5668;&#x8BC1;&#x4E66;&#x53D6;&#x51FA;&#x7684;&#x516C;&#x94A5;&#x52A0;&#x5BC6;&#x540E;&#x7684;premaster secret&#xFF0C;&#x8FD9;&#x91CC;&#x7684;premaster secret&#x5176;&#x5B9E;&#x662F;&#x53E6;&#x4E00;&#x4E2A;&#x968F;&#x673A;&#x6570;</li>
<li>&#x52A0;&#x5BC6;&#x7EA6;&#x5B9A;&#x6539;&#x53D8;&#x901A;&#x77E5;&#xFF0C;&#x901A;&#x77E5;&#x670D;&#x52A1;&#x5668;&#xFF0C;&#x4EE5;&#x540E;&#x7684;&#x901A;&#x4FE1;&#x90FD;&#x9002;&#x7528;&#x534F;&#x5546;&#x597D;&#x7684;&#x52A0;&#x5BC6;&#x65B9;&#x6CD5;&#x548C;&#x5BC6;&#x94A5;&#x8FDB;&#x884C;&#x52A0;&#x5BC6;</li>
<li>&#x5BA2;&#x6237;&#x7AEF;&#x63E1;&#x624B;&#x7ED3;&#x675F;&#x901A;&#x77E5;&#x3002;&#x8FD9;&#x4E2A;&#x62A5;&#x6587;&#x4E5F;&#x662F;&#x9A8C;&#x8BC1;&#x6D88;&#x606F;&#xFF0C;&#x662F;&#x524D;&#x9762;&#x53D1;&#x9001;&#x7684;&#x6240;&#x6709;&#x5185;&#x5BB9;&#x7684;&#x54C8;&#x5E0C;&#x503C;&#xFF0C;&#x7528;&#x6765;&#x4F9B;&#x670D;&#x52A1;&#x5668;&#x6821;&#x9A8C;&#x3002;</li>
</ol>
<h5 id>&#x670D;&#x52A1;&#x5668;&#x6700;&#x540E;&#x786E;&#x8BA4;</h5>
<p>&#x8FD9;&#x662F;&#x63E1;&#x624B;&#x8FC7;&#x7A0B;&#x7684;&#x6700;&#x540E;&#x4E00;&#x6B65;&#xFF0C;&#x670D;&#x52A1;&#x5668;&#x4F1A;&#x628A;&#x4EE5;&#x4E0B;&#x4FE1;&#x606F;&#x53D1;&#x9001;&#x7ED9;&#x5BA2;&#x6237;&#x7AEF;&#xFF1A;</p>
<ol>
<li>&#x52A0;&#x5BC6;&#x7EA6;&#x5B9A;&#x6539;&#x53D8;&#x901A;&#x77E5;&#xFF0C;&#x901A;&#x77E5;&#x5BA2;&#x6237;&#x7AEF;&#xFF0C;&#x4EE5;&#x540E;&#x7684;&#x901A;&#x4FE1;&#x90FD;&#x9002;&#x7528;&#x534F;&#x5546;&#x597D;&#x7684;&#x52A0;&#x5BC6;&#x65B9;&#x6CD5;&#x548C;&#x5BC6;&#x94A5;&#x8FDB;&#x884C;&#x52A0;&#x5BC6;</li>
<li>&#x670D;&#x52A1;&#x5668;&#x63E1;&#x624B;&#x7ED3;&#x675F;&#x901A;&#x77E5;&#xFF0C;&#x8BE5;&#x62A5;&#x6587;&#x4E5F;&#x4F5C;&#x4E3A;&#x6821;&#x9A8C;&#x6D88;&#x606F;&#xFF0C;&#x4F9B;&#x5BA2;&#x6237;&#x7AEF;&#x9A8C;&#x8BC1;&#x3002;</li>
</ol>
<p>&#x5230;&#x8FD9;&#x4E2A;&#x65F6;&#x5019;&#xFF0C;&#x5BA2;&#x6237;&#x7AEF;&#x548C;&#x670D;&#x52A1;&#x5668;&#x540C;&#x65F6;&#x62E5;&#x6709;&#x4E86;3&#x4E2A;&#x968F;&#x673A;&#x6570;&#xFF0C;&#x4F7F;&#x7528;&#x8FD9;&#x4E09;&#x4E2A;&#x968F;&#x673A;&#x6570;&#x751F;&#x6210;&#x7684;&#x5BC6;&#x94A5;&#xFF0C;&#x5C06;&#x88AB;&#x7528;&#x4E8E;&#x540E;&#x7EED;&#x901A;&#x4FE1;&#x7684;&#x5BF9;&#x79F0;&#x52A0;&#x5BC6;&#x3002;&#x4E5F;&#x5C31;&#x662F;&#x8BF4;&#xFF0C;&#x53EA;&#x6709;&#x63E1;&#x624B;&#x8FC7;&#x7A0B;&#x624D;&#x6709;&#x975E;&#x5BF9;&#x79F0;&#x52A0;&#x5BC6;&#xFF0C;&#x975E;&#x5BF9;&#x79F0;&#x52A0;&#x5BC6;&#x662F;&#x6BD4;&#x8F83;&#x6162;&#x7684;&#xFF0C;&#x56E0;&#x6B64;&#x53EA;&#x7528;&#x4E8E;&#x5EFA;&#x7ACB;&#x5B89;&#x5168;&#x7684;&#x4FE1;&#x9053;&#xFF0C;Payload&#x7684;&#x4F20;&#x8F93;&#x90FD;&#x662F;&#x5BF9;&#x79F0;&#x52A0;&#x5BC6;&#x7684;&#xFF0C;&#x5BF9;&#x79F0;&#x52A0;&#x5BC6;&#x7684;&#x901F;&#x5EA6;&#x548C;&#x8D44;&#x6E90;&#x5360;&#x7528;&#x6BD4;&#x975E;&#x5BF9;&#x79F0;&#x52A0;&#x5BC6;&#x90FD;&#x8981;&#x597D;&#xFF0C;&#x56E0;&#x6B64;&#x5BF9;&#x6027;&#x80FD;&#x7684;&#x5F71;&#x54CD;&#x662F;&#x5F88;&#x5C0F;&#x7684;&#x3002;</p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[Port leveldb to Android]]></title><description><![CDATA[<!--kg-card-begin: markdown--><p>As leveldb has already implemented platform-dependent interfaces, porting leveldb is pretty simple. Cross compile the source code on Linux or build with NDK are both OK. Here&apos;s my NDK build script. It compiles with NDK r13b and leveldb 1.20.</p>
<script src="https://gist.github.com/shunix/39a77a301dad6b7793288fbb4470455f.js"></script>
<script src="https://gist.github.com/shunix/fe16444d6ca0d209bd41685beea59d08.js"></script>
<p>You can get the full source code at</p>]]></description><link>https://shunix.com/port-leveldb-to-android/</link><guid isPermaLink="false">60812ae62b3f873b19511ebd</guid><category><![CDATA[技术文章]]></category><dc:creator><![CDATA[Shunix]]></dc:creator><pubDate>Fri, 07 Jul 2017 09:39:26 GMT</pubDate><content:encoded><![CDATA[<!--kg-card-begin: markdown--><p>As leveldb has already implemented platform-dependent interfaces, porting leveldb is pretty simple. Cross compile the source code on Linux or build with NDK are both OK. Here&apos;s my NDK build script. It compiles with NDK r13b and leveldb 1.20.</p>
<script src="https://gist.github.com/shunix/39a77a301dad6b7793288fbb4470455f.js"></script>
<script src="https://gist.github.com/shunix/fe16444d6ca0d209bd41685beea59d08.js"></script>
<p>You can get the full source code at <a href="https://github.com/shunix/leveldb-ndk.git">leveldb-ndk</a></p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[Steam升级指南]]></title><description><![CDATA[<!--kg-card-begin: markdown--><h4 id>&#x524D;&#x8A00;</h4>
<p>&#x6DF7;&#x4E86;&#x8FD9;&#x4E48;&#x4E45;&#x7684;steam&#xFF0C;&#x5E10;&#x53F7;&#x7B49;&#x7EA7;&#x4E00;&#x76F4;&#x5F88;&#x4F4E;&#xFF0C;&#x672C;&#x6765;&#x53EA;&#x662F;&#x51C6;&#x5907;&#x5347;&#x4E00;&#x4E0B;&#x7B49;&#x7EA7;&#x7684;&#xFF0C;&#x6CA1;&#x60F3;&#x5230;&#x5C31;&#x5165;&#x4E86;&#x6302;&#x5361;&#x7684;&#x5751;&#xFF0C;&#x8FD9;&#x91CC;&#x5199;&#x4E00;&#x7BC7;&#x653B;&#x7565;</p>]]></description><link>https://shunix.com/steam-levelup-guide/</link><guid isPermaLink="false">60812ae62b3f873b19511ebb</guid><category><![CDATA[随想杂谈]]></category><dc:creator><![CDATA[Shunix]]></dc:creator><pubDate>Sat, 22 Apr 2017 18:38:36 GMT</pubDate><content:encoded><![CDATA[<!--kg-card-begin: markdown--><h4 id>&#x524D;&#x8A00;</h4>
<p>&#x6DF7;&#x4E86;&#x8FD9;&#x4E48;&#x4E45;&#x7684;steam&#xFF0C;&#x5E10;&#x53F7;&#x7B49;&#x7EA7;&#x4E00;&#x76F4;&#x5F88;&#x4F4E;&#xFF0C;&#x672C;&#x6765;&#x53EA;&#x662F;&#x51C6;&#x5907;&#x5347;&#x4E00;&#x4E0B;&#x7B49;&#x7EA7;&#x7684;&#xFF0C;&#x6CA1;&#x60F3;&#x5230;&#x5C31;&#x5165;&#x4E86;&#x6302;&#x5361;&#x7684;&#x5751;&#xFF0C;&#x8FD9;&#x91CC;&#x5199;&#x4E00;&#x7BC7;&#x653B;&#x7565;&#x5427;&#xFF0C;&#x8BB2;&#x8BB2;&#x5173;&#x4E8E;steam&#x5347;&#x7EA7;&#x7684;&#x4E00;&#x5207;&#x3002;</p>
<h4 id>&#x80CC;&#x666F;&#x77E5;&#x8BC6;</h4>
<h6 id>&#x4EC0;&#x4E48;&#x662F;&#x559C;&#x52A0;&#x4E00;&#xFF1F;</h6>
<p>&#x672C;&#x610F;&#x662F;&#x8BF4;&#xFF0C;&#x4E70;&#x4E86;&#x4E5F;&#x4E0D;&#x73A9;&#xFF0C;&#x53EA;&#x662F;&#x8BA9;&#x5E93;&#x5B58;&#x6E38;&#x620F;&#x6570;&#x91CF;&#x52A0;&#x4E00;&#x7684;&#x884C;&#x4E3A;&#x3002;&#x540E;&#x6765;&#x559C;&#x52A0;&#x4E00;&#x6E38;&#x620F;&#x4E5F;&#x7528;&#x6765;&#x6307;&#x90A3;&#x4E9B;&#x8D28;&#x91CF;&#x4F4E;&#x4E0B;&#xFF0C;&#x4F46;&#x662F;&#x5F88;&#x4FBF;&#x5B9C;&#x7684;&#x6E38;&#x620F;&#xFF0C;&#x901A;&#x5E38;&#x6765;&#x8BF4;&#xFF0C;&#x8FD9;&#x4E9B;&#x6E38;&#x620F;&#x51E0;&#x4E4E;&#x6CA1;&#x6709;&#x53EF;&#x73A9;&#x6027;&#xFF0C;&#x552F;&#x4E00;&#x7684;&#x4F18;&#x70B9;&#x5C31;&#x662F;&#x4FBF;&#x5B9C;&#x3002;&#x50CF;&#x4E0B;&#x9762;&#x8FD9;&#x5F20;&#x56FE;&#x91CC;&#xFF0C;&#x8FD9;&#x4E9B;&#x88AB;&#x6211;&#x9690;&#x85CF;&#x6389;&#x7684;&#xFF0C;&#x90FD;&#x662F;&#x559C;&#x52A0;&#x4E00;&#x6E38;&#x620F;&#x3002;<br>
<img src="https://raw.githubusercontent.com/Shunix/BlogImages/master/20170422_steam_plus_one.png" alt="&#x559C;&#x52A0;&#x4E00;" loading="lazy"></p>
<h6 id="steam">&#x4EC0;&#x4E48;&#x662F;steam&#x96C6;&#x6362;&#x5F0F;&#x5361;&#x724C;&#xFF1F;</h6>
<p>&#x867D;&#x7136;&#x53EB;&#x96C6;&#x6362;&#x5F0F;&#x5361;&#x724C;&#xFF0C;&#x4F46;&#x662F;&#x5E76;&#x4E0D;&#x80FD;&#x62FF;&#x6765;&#x73A9;&#x5361;&#x724C;&#x6E38;&#x620F;&#xFF0C;&#x552F;&#x4E00;&#x7684;&#x4F5C;&#x7528;&#x5C31;&#x662F;&#x62FF;&#x6765;&#x5408;&#x6210;&#x5FBD;&#x7AE0;&#xFF0C;&#x5C31;&#x50CF;&#x4E0B;&#x9762;&#x8FD9;&#x4E24;&#x5F20;&#x56FE;&#x4E00;&#x6837;&#xFF0C;&#x5408;&#x6210;&#x5B8C;&#x7684;&#x5FBD;&#x7AE0;&#x4F1A;&#x51FA;&#x73B0;&#x5728;&#x4E2A;&#x4EBA;&#x8D44;&#x6599;&#x9875;&#x3002;<br>
<img src="https://raw.githubusercontent.com/Shunix/BlogImages/master/20170422_steam_badge_1.png" alt="&#x5FBD;&#x7AE0;&#x9875;" loading="lazy"><br>
<img src="https://raw.githubusercontent.com/Shunix/BlogImages/master/20170422_steam_badge_2.png" alt="&#x4E2A;&#x4EBA;&#x8D44;&#x6599;&#x9875;&#x5FBD;&#x7AE0;" loading="lazy"><br>
&#x6BCF;&#x4E2A;&#x6E38;&#x620F;&#x4F1A;&#x6389;&#x843D;&#x603B;&#x6570;&#x4E00;&#x534A;&#x5DE6;&#x53F3;&#x7684;&#x5361;&#x724C;&#xFF0C;&#x4E3E;&#x4E2A;&#x4F8B;&#x5B50;&#xFF0C;Don&apos;t Starve&#x4E00;&#x5171;&#x6709;5&#x5F20;&#x5361;&#x724C;&#xFF0C;&#x90A3;&#x4E48;&#x901A;&#x8FC7;&#x6E38;&#x620F;&#x53EF;&#x4EE5;&#x514D;&#x8D39;&#x6389;&#x843D;&#x7684;&#x5C31;&#x662F;3&#x5F20;&#xFF08;&#x5411;&#x4E0A;&#x53D6;&#x6574;&#xFF09;&#xFF0C;&#x6389;&#x843D;&#x7684;&#x5361;&#x724C;&#x662F;&#x4F1A;&#x91CD;&#x590D;&#x7684;&#xFF0C;&#x96C6;&#x9F50;&#x4E00;&#x6574;&#x5957;&#x5361;&#x724C;&#x5C31;&#x53EF;&#x4EE5;&#x5408;&#x6210;&#x5FBD;&#x7AE0;&#xFF0C;&#x81EA;&#x5DF1;&#x6CA1;&#x6709;&#x7684;&#x5361;&#x724C;&#x53EF;&#x4EE5;&#x901A;&#x8FC7;&#x548C;&#x5176;&#x4ED6;&#x73A9;&#x5BB6;&#x4EA4;&#x6362;&#x6216;&#x8005;&#x76F4;&#x63A5;&#x8D2D;&#x4E70;&#x5F97;&#x5230;&#x3002;&#x5FBD;&#x7AE0;&#x4E5F;&#x662F;&#x53EF;&#x4EE5;&#x5347;&#x7EA7;&#x7684;&#xFF0C;&#x6700;&#x9AD8;&#x80FD;&#x5347;&#x5230;5&#x7EA7;&#x3002;<br>
&#x56E0;&#x4E3A;steam&#x6709;2&#x5C0F;&#x65F6;&#x5185;&#x6E38;&#x620F;&#x65F6;&#x95F4;&#x53EF;&#x4EE5;&#x9000;&#x6B3E;&#x7684;&#x89C4;&#x5B9A;&#xFF0C;&#x6240;&#x4EE5;&#x5927;&#x90E8;&#x5206;&#x5361;&#x724C;&#x90FD;&#x8981;2&#x5C0F;&#x65F6;&#x4E4B;&#x540E;&#x624D;&#x4F1A;&#x6389;&#x843D;&#xFF08;&#x636E;&#x8BF4;&#x4ECE;&#x6765;&#x6CA1;&#x9000;&#x8FC7;&#x6B3E;&#x7684;&#x73A9;&#x5BB6;&#x6CA1;&#x6709;&#x8FD9;&#x4E2A;&#x9650;&#x5236;&#xFF0C;&#x4E0D;&#x786E;&#x5B9A;&#x8FD9;&#x4E2A;&#x8BF4;&#x6CD5;&#x7684;&#x771F;&#x5B9E;&#x6027;&#xFF09;&#x3002;&#x5E73;&#x5747;&#x4E0B;&#x6765;&#x6BCF;&#x534A;&#x5C0F;&#x65F6;&#x4F1A;&#x6389;&#x843D;&#x4E00;&#x5F20;&#x5361;&#x724C;&#x3002;<br>
&#x5361;&#x724C;&#x5206;&#x4E3A;&#x666E;&#x901A;&#x8FB9;&#x6846;&#x548C;&#x95EA;&#x4EAE;&#x8FB9;&#x6846;&#x4E24;&#x79CD;&#xFF0C;&#x95EA;&#x5361;&#x4EF7;&#x683C;&#x901A;&#x5E38;&#x90FD;&#x662F;&#x666E;&#x5361;&#x7684;&#x597D;&#x51E0;&#x500D;&#xFF0C;&#x53EF;&#x4EE5;&#x7528;&#x6765;&#x5408;&#x6210;&#x95EA;&#x4EAE;&#x5FBD;&#x7AE0;&#xFF0C;&#x95EA;&#x4EAE;&#x5FBD;&#x7AE0;&#x901A;&#x5E38;&#x4F1A;&#x66F4;&#x597D;&#x770B;&#x4E00;&#x70B9;&#x3002;&#x56E0;&#x4E3A;&#x95EA;&#x5361;&#x7684;&#x7A00;&#x7F3A;&#x6027;&#xFF0C;&#x6240;&#x4EE5;&#x4EF7;&#x683C;&#x90FD;&#x6807;&#x7684;&#x5F88;&#x968F;&#x6027;&#xFF0C;&#x90E8;&#x5206;&#x597D;&#x770B;&#x4E00;&#x70B9;&#x7684;&#x95EA;&#x5361;&#xFF0C;&#x4EF7;&#x683C;&#x662F;&#x6BD4;&#x8F83;&#x79BB;&#x8C31;&#x7684;&#x3002;&#x4E00;&#x7EA7;&#x7684;&#x95EA;&#x4EAE;&#x5FBD;&#x7AE0;&#x53EF;&#x80FD;&#x6BD4;&#x4E94;&#x7EA7;&#x7684;&#x666E;&#x901A;&#x5FBD;&#x7AE0;&#x8FD8;&#x8981;&#x8D35;&#x3002;</p>
<h6 id>&#x4EC0;&#x4E48;&#x662F;&#x8865;&#x5145;&#x5305;&#xFF1F;</h6>
<p>&#x8865;&#x5145;&#x5305;&#x662F;&#x4E00;&#x4E2A;&#x5305;&#x542B;&#x4E09;&#x5F20;&#x5361;&#x724C;&#x7684;&#x5305;&#xFF0C;&#x5F53;&#x4E00;&#x4E2A;&#x6E38;&#x620F;&#x6CA1;&#x6709;&#x53EF;&#x4EE5;&#x6389;&#x843D;&#x7684;&#x5361;&#x724C;&#x4E4B;&#x540E;&#xFF0C;&#x5C31;&#x6709;&#x4E86;&#x83B7;&#x53D6;&#x8865;&#x5145;&#x5305;&#x7684;&#x8D44;&#x683C;&#xFF0C;&#x53EA;&#x8981;&#x6BCF;&#x5468;&#x4FDD;&#x6301;&#x767B;&#x5F55;&#xFF0C;&#x5C31;&#x6709;&#x53EF;&#x80FD;&#x83B7;&#x53D6;&#x968F;&#x673A;&#x6389;&#x843D;&#x7684;&#x8865;&#x5145;&#x5305;&#xFF0C;&#x8865;&#x5145;&#x5305;&#x662F;&#x83B7;&#x53D6;&#x95EA;&#x5361;&#x7684;&#x4E3B;&#x8981;&#x9014;&#x5F84;&#x3002;</p>
<h6 id>&#x4EC0;&#x4E48;&#x662F;&#x6148;&#x5584;&#x5305;&#xFF1F;</h6>
<p>&#x5927;&#x90E8;&#x5206;&#x4EBA;&#x5728;steam&#x4E70;&#x6E38;&#x620F;&#x90FD;&#x662F;&#x7B49;&#x5230;&#x6253;&#x6298;&#x624D;&#x4E70;&#xFF0C;&#x5176;&#x5B9E;&#x8FD8;&#x6709;&#x53E6;&#x4E00;&#x79CD;&#x83B7;&#x53D6;&#x4F4E;&#x4EF7;&#x6E38;&#x620F;&#x7684;&#x9014;&#x5F84;&#xFF0C;&#x5C31;&#x662F;&#x6148;&#x5584;&#x5305;&#x3002;&#x6148;&#x5584;&#x5305;&#x4F1A;&#x628A;&#x4E00;&#x4E9B;&#x6E38;&#x620F;&#x6253;&#x6210;&#x51E0;&#x4E2A;&#x5305;&#xFF0C;&#x5206;&#x4E3A;&#x57FA;&#x7840;&#x5305;&#xFF0C;&#x5747;&#x4EF7;&#x5305;&#x548C;&#x5168;&#x4EF7;&#x5305;&#xFF0C;&#x4ED8;&#x5BF9;&#x5E94;&#x7684;&#x4EF7;&#x94B1;&#x5C31;&#x80FD;&#x83B7;&#x5F97;&#x5305;&#x5185;&#x7684;&#x6E38;&#x620F;&#xFF0C;&#x6536;&#x5165;&#x7684;&#x4E00;&#x90E8;&#x5206;&#x4F1A;&#x62FF;&#x53BB;&#x505A;&#x6148;&#x5584;&#x3002;&#x57FA;&#x7840;&#x5305;&#x4E00;&#x822C;&#x662F;&#x6700;&#x4F4E;1&#x7F8E;&#x5143;&#xFF0C;&#x5747;&#x4EF7;&#x5305;&#x5C31;&#x662F;&#x6240;&#x6709;&#x8D2D;&#x4E70;&#x4E86;&#x8BE5;&#x6148;&#x5584;&#x5305;&#x7684;&#x7528;&#x6237;&#x6240;&#x652F;&#x4ED8;&#x91D1;&#x989D;&#x7684;&#x5747;&#x4EF7;&#xFF0C;&#x8FD9;&#x4E2A;&#x4F1A;&#x968F;&#x7740;&#x65F6;&#x95F4;&#x4E0A;&#x6DA8;&#xFF0C;&#x6240;&#x4EE5;&#x8981;&#x4E70;&#x7684;&#x8BDD;&#x5C3D;&#x5FEB;&#x51FA;&#x624B;&#xFF0C;&#x5168;&#x4EF7;&#x5305;&#x5C31;&#x6CA1;&#x6709;&#x4E0A;&#x9650;&#x4E86;&#xFF0C;&#x60F3;&#x7ED9;&#x591A;&#x5C11;&#x90FD;&#x884C;&#x3002;</p>
<h4 id="steam">Steam&#x7B49;&#x7EA7;</h4>
<h6 id="steam">Steam&#x7B49;&#x7EA7;&#x6709;&#x4EC0;&#x4E48;&#x4F5C;&#x7528;&#xFF1F;</h6>
<p>&#x9996;&#x5148;&#xFF0C;&#x4E2A;&#x4EBA;&#x8D44;&#x6599;&#x9875;&#x5C55;&#x793A;&#x7684;&#x597D;&#x53CB;&#x53EA;&#x6709;6&#x4E2A;&#xFF0C;&#x8FD9;&#x4E2A;&#x987A;&#x5E8F;&#x5C31;&#x662F;&#x6309;&#x7B49;&#x7EA7;&#x6392;&#x7684;&#xFF0C;&#x7B49;&#x7EA7;&#x9AD8;&#x7684;&#x8BDD;&#xFF0C;&#x4F1A;&#x6392;&#x5728;&#x522B;&#x4EBA;&#x8D44;&#x6599;&#x9875;&#x7684;&#x524D;&#x9762;&#x3002;&#x7136;&#x540E;&#x6BCF;&#x5347;&#x4E00;&#x7EA7;&#x90FD;&#x4F1A;&#x589E;&#x52A0;5&#x4E2A;&#x597D;&#x53CB;&#x4F4D;&#x3002;&#x8865;&#x5145;&#x5305;&#x7684;&#x6389;&#x843D;&#x7387;&#x4E5F;&#x4F1A;&#x968F;&#x7740;&#x7B49;&#x7EA7;&#x7684;&#x63D0;&#x9AD8;&#x800C;&#x589E;&#x52A0;&#x3002;10&#x7EA7;+20%&#x7684;&#x6389;&#x843D;&#x7387;&#xFF0C;20&#x7EA7;+40%&#x7684;&#x6389;&#x843D;&#x7387;&#xFF0C;30&#x7EA7;+60%&#x7684;&#x6389;&#x843D;&#x7387;&#xFF0C;&#x4F9D;&#x6B64;&#x7C7B;&#x63A8;&#x3002;&#x6BCF;&#x5347;10&#x7EA7;&#x8FD8;&#x4F1A;&#x9001;&#x4E00;&#x4E2A;&#x5C55;&#x67DC;&#xFF0C;&#x53EF;&#x4EE5;&#x7528;&#x6765;&#x653E;&#x81EA;&#x5B9A;&#x4E49;&#x7684;&#x5185;&#x5BB9;&#xFF0C;&#x50CF;&#x4E0B;&#x9762;&#x8FD9;&#x6837;&#xFF1A;<br>
<img src="https://raw.githubusercontent.com/Shunix/BlogImages/master/20170423_steam_showcase.png" alt="&#x5C55;&#x67DC;" loading="lazy"><br>
&#x7B80;&#x5355;&#x6765;&#x8BF4;&#xFF0C;&#x5C31;&#x662F;&#x7B49;&#x7EA7;&#x8D8A;&#x9AD8;&#x8D8A;&#x65B9;&#x4FBF;&#x88C5;&#x903C;&#x3002;</p>
<h6 id>&#x5982;&#x4F55;&#x63D0;&#x5347;&#x7B49;&#x7EA7;&#xFF1F;</h6>
<p>&#x76EE;&#x524D;&#x53EA;&#x80FD;&#x901A;&#x8FC7;&#x4E70;&#x6E38;&#x620F;&#x6216;&#x8005;&#x5408;&#x6210;&#x5FBD;&#x7AE0;&#x6765;&#x83B7;&#x53D6;&#x7ECF;&#x9A8C;&#xFF0C;&#x4E70;&#x6E38;&#x620F;&#x80FD;&#x62FF;&#x5230;&#x7684;&#x7ECF;&#x9A8C;&#x592A;&#x5C11;&#x4E86;&#xFF0C;&#x4E3B;&#x8981;&#x9014;&#x5F84;&#x8FD8;&#x662F;&#x5408;&#x5FBD;&#x7AE0;&#x3002;&#x6BCF;&#x6B21;&#x5408;&#x6210;&#x6216;&#x8005;&#x5347;&#x7EA7;&#x5FBD;&#x7AE0;&#xFF0C;&#x4F1A;&#x83B7;&#x5F97;100&#x7ECF;&#x9A8C;&#xFF0C;&#x4ECE;0~10&#x7EA7;&#x6BCF;&#x7EA7;&#x8981;100&#x7ECF;&#x9A8C;&#xFF0C;10~20&#x7EA7;&#x6BCF;&#x7EA7;&#x8981;200&#x7ECF;&#x9A8C;&#xFF0C;20~30&#x7EA7;&#x6BCF;&#x7EA7;&#x8981;300&#x7ECF;&#x9A8C;&#xFF0C;&#x4F9D;&#x6B64;&#x7C7B;&#x63A8;&#x3002;&#x6211;&#x4E2A;&#x4EBA;&#x89C9;&#x5F97;&#xFF0C;30&#x7EA7;&#x662F;&#x4E00;&#x4E2A;&#x6027;&#x4EF7;&#x6BD4;&#x6BD4;&#x8F83;&#x9AD8;&#x7684;&#x7B49;&#x7EA7;&#xFF0C;&#x89E3;&#x9501;&#x4E86;3&#x4E2A;&#x5C55;&#x67DC;&#xFF0C;400&#x4E2A;&#x597D;&#x53CB;&#x4F4D;&#xFF0C;&#x57FA;&#x672C;&#x4E0A;&#x4E5F;&#x591F;&#x7528;&#x4E86;&#x3002;</p>
<h6 id>&#x5982;&#x4F55;&#x9AD8;&#x6548;&#x7ECF;&#x6D4E;&#x5730;&#x63D0;&#x5347;&#x7B49;&#x7EA7;&#xFF1F;</h6>
<p>&#x7EC8;&#x4E8E;&#x5207;&#x5165;&#x6B63;&#x9898;&#x4E86;&#xFF0C;steam&#x4E0A;&#x7684;&#x73A9;&#x5BB6;&#xFF0C;&#x571F;&#x8C6A;&#x6BD5;&#x7ADF;&#x662F;&#x5C11;&#x6570;&#x3002;&#x5927;&#x90E8;&#x5206;&#x90FD;&#x5E0C;&#x671B;&#x94B1;&#x82B1;&#x5728;&#x4E70;&#x6E38;&#x620F;&#x4E0A;&#xFF0C;&#x7B49;&#x7EA7;&#x8FD9;&#x79CD;&#x4E1C;&#x897F;&#xFF0C;&#x6700;&#x597D;&#x5C11;&#x82B1;&#x70B9;&#x94B1;&#x3002;&#x5F53;&#x7136;&#xFF0C;&#x6211;&#x5E73;&#x65F6;&#x5DE5;&#x4F5C;&#x4E5F;&#x5F88;&#x5FD9;&#xFF0C;&#x4E0D;&#x53EF;&#x80FD;&#x50CF;&#x67D0;&#x4E9B;&#x5B66;&#x751F;&#x515A;&#x4E00;&#x6837;&#xFF0C;&#x6574;&#x5929;&#x6DF7;&#x8FF9;&#x5728;&#x793E;&#x533A;&#x5E02;&#x573A;&#xFF0C;&#x901A;&#x8FC7;&#x4F4E;&#x4E70;&#x9AD8;&#x5356;&#x6765;&#x8D5A;&#x5DEE;&#x4EF7;&#x3002;&#x6240;&#x4EE5;&#x8FD9;&#x91CC;&#x603B;&#x7ED3;&#x4E86;&#x4E00;&#x4E0B;&#xFF0C;&#x600E;&#x4E48;&#x6837;&#x624D;&#x80FD;&#x76F8;&#x5BF9;&#x9AD8;&#x6548;&#x7ECF;&#x6D4E;&#x5730;&#x63D0;&#x5347;&#x7B49;&#x7EA7;&#x3002;</p>
<ol>
<li>&#x9996;&#x5148;&#x662F;&#x591A;&#x4E70;&#x559C;&#x52A0;&#x4E00;&#x6E38;&#x620F;&#xFF0C;&#x5F53;&#x7136;&#xFF0C;&#x8981;&#x4E70;&#x80FD;&#x6389;&#x5361;&#x7684;&#x90A3;&#x79CD;&#xFF0C;&#x4E00;&#x822C;&#x6765;&#x8BF4;&#xFF0C;steam&#x7279;&#x60E0;&#x91CC;&#x9762;&#xFF0C;2&#x5757;&#x94B1;&#x4EE5;&#x4E0B;&#x7684;&#x90FD;&#x53EF;&#x4EE5;&#x76F4;&#x63A5;&#x4E70;&#x4E86;&#xFF0C;&#x7136;&#x540E;&#x5C31;&#x662F;&#x591A;&#x5173;&#x6CE8;&#x6148;&#x5584;&#x5305;&#xFF0C;&#x5982;&#x679C;&#x53EA;&#x662F;&#x4E3A;&#x4E86;&#x6302;&#x5361;&#x7684;&#x8BDD;&#xFF0C;&#x90FD;&#x4E70;&#x57FA;&#x7840;&#x5305;&#x5C31;&#x591F;&#x4E86;&#xFF0C;&#x5E73;&#x644A;&#x4E0B;&#x6765;&#xFF0C;&#x6BCF;&#x4E2A;&#x6E38;&#x620F;&#x4E5F;&#x5C31;2&#x5757;&#x94B1;&#x4E0D;&#x5230;&#x70B9;&#x3002;&#x8FD9;&#x91CC;&#x63A8;&#x8350;&#x51E0;&#x4E2A;&#x65B9;&#x4FBF;&#x4E70;&#x559C;&#x52A0;&#x4E00;&#x6302;&#x5361;&#x6E38;&#x620F;&#x7684;&#x6148;&#x5584;&#x5305;&#x7F51;&#x7AD9;&#xFF1A;<br>
<a href="https://www.humblebundle.com/">Humble Bundle</a>&#xFF0C;&#x5927;&#x540D;&#x9F0E;&#x9F0E;&#x7684;Humble Bundle&#xFF0C;&#x6708;&#x5305;&#x8D28;&#x91CF;&#x633A;&#x9AD8;&#x7684;&#xFF0C;&#x4E0D;&#x6B62;&#x53EF;&#x4EE5;&#x4E70;&#x559C;&#x52A0;&#x4E00;<br>
<a href="https://www.indiegala.com/">IndieGala</a>&#xFF0C;&#x8FD9;&#x4E2A;&#x5EFA;&#x8BAE;&#x76F4;&#x63A5;&#x53BB;&#x6DD8;&#x5B9D;&#x4E70;&#x6B22;&#x4E50;&#x65F6;&#x5149;&#x5305;&#xFF0C;&#x76F8;&#x5F53;&#x4E8E;&#x56E2;&#x8D2D;&#xFF0C;&#x8981;&#x4FBF;&#x5B9C;&#x5F88;&#x591A;<br>
<a href="http://bundle.ccyycn.com/">&#x9A70;&#x6E38;</a>&#xFF0C;&#x56FD;&#x5185;&#x7F51;&#x7AD9;&#xFF0C;&#x7231;&#x5361;&#x5305;&#x6E38;&#x620F;&#x5355;&#x4EF7;&#x7279;&#x522B;&#x4FBF;&#x5B9C;&#xFF0C;&#x5927;&#x7EA6;&#x51E0;&#x6BDB;&#x94B1;&#x4E00;&#x4E2A;&#xFF0C;&#x4F46;&#x662F;&#x9664;&#x4E86;&#x4FBF;&#x5B9C;&#x4E5F;&#x6CA1;&#x522B;&#x7684;&#x4F18;&#x70B9;&#x4E86;</li>
<li>&#x7136;&#x540E;&#x5C31;&#x662F;&#x5173;&#x4E8E;&#x5408;&#x6210;&#x5FBD;&#x7AE0;&#x7684;&#x7B56;&#x7565;&#x4E86;&#x3002;&#x6BCF;&#x4E2A;&#x5FBD;&#x7AE0;&#x5408;&#x6210;&#x90FD;&#x662F;100&#x7ECF;&#x9A8C;&#xFF0C;&#x4F46;&#x662F;&#x6240;&#x9700;&#x8981;&#x7684;&#x6210;&#x672C;&#x662F;&#x5927;&#x4E0D;&#x76F8;&#x540C;&#x7684;&#xFF0C;&#x4E00;&#x4E9B;&#x597D;&#x770B;&#x7684;&#x5FBD;&#x7AE0;&#xFF0C;&#x6216;&#x8005;&#x70ED;&#x95E8;&#x6E38;&#x620F;&#x7684;&#x5FBD;&#x7AE0;&#xFF0C;&#x5408;&#x6210;&#x6240;&#x9700;&#x8981;&#x7684;&#x5361;&#x7247;&#x5C31;&#x4F1A;&#x5F88;&#x9AD8;&#xFF0C;&#x51E0;&#x5757;&#x94B1;&#x4E00;&#x5F20;&#x7684;&#x5361;&#x7247;&#x4E5F;&#x662F;&#x6709;&#x7684;&#x3002;&#x4E00;&#x4E9B;&#x5356;&#x76F8;&#x4E0D;&#x597D;&#x7684;&#x5FBD;&#x7AE0;&#xFF0C;&#x5408;&#x6210;&#x6240;&#x9700;&#x8981;&#x7684;&#x5361;&#x7247;&#x5C31;&#x4F1A;&#x5F88;&#x4FBF;&#x5B9C;&#xFF0C;&#x4E03;&#x516B;&#x5206;&#x94B1;&#x7684;&#x4E5F;&#x6709;&#x5F88;&#x591A;&#x3002;&#x65E2;&#x7136;&#x6211;&#x4EEC;&#x7684;&#x76EE;&#x7684;&#x53EA;&#x662F;&#x8981;&#x5347;&#x7EA7;&#xFF0C;&#x90A3;&#x5C31;&#x4E0D;&#x7528;&#x7BA1;&#x5FBD;&#x7AE0;&#x597D;&#x4E0D;&#x597D;&#x770B;&#x4E86;&#x3002;&#x8FD9;&#x91CC;&#x5EFA;&#x8BAE;&#xFF0C;&#x6389;&#x843D;&#x7684;&#x5361;&#x7247;&#xFF0C;&#x552E;&#x4EF7;&#x9AD8;&#x4E8E;0.5&#x5143;&#x7684;&#xFF0C;&#x76F4;&#x63A5;&#x4E0A;&#x67B6;&#x5356;&#x6389;&#xFF0C;&#x6302;&#x5E02;&#x573A;&#x4EF7;&#x5C31;&#x884C;&#xFF0C;&#x5F88;&#x5FEB;&#x80FD;&#x5356;&#x6389;&#x3002;&#x4F4E;&#x4E8E;0.5&#x5143;&#x7684;&#xFF0C;&#x53EF;&#x4EE5;&#x8003;&#x8651;&#x7559;&#x4E0B;&#x5408;&#x6210;&#x5FBD;&#x7AE0;&#x3002;&#x6700;&#x540E;&#x5E73;&#x5747;&#x7B97;&#x4E0B;&#x6765;&#xFF0C;&#x4E0D;&#x7B97;&#x4E70;&#x6E38;&#x620F;&#x7684;&#x94B1;&#xFF0C;&#x6BCF;100&#x7ECF;&#x9A8C;&#x7684;&#x6210;&#x672C;&#x5E94;&#x8BE5;&#x662F;&#x5728;1&#x5757;&#x94B1;&#x5DE6;&#x53F3;&#x7684;&#xFF0C;&#x5347;&#x5230;30&#x7EA7;&#x5927;&#x6982;&#x53EA;&#x9700;&#x8981;60&#x5757;&#x94B1;&#xFF0C;&#x4E5F;&#x5C31;&#x662F;&#x4E00;&#x4E2A;&#x6E38;&#x620F;&#x7684;&#x4EF7;&#x94B1;&#x3002;</li>
<li>&#x5408;&#x6210;&#x5FBD;&#x7AE0;&#x4F1A;&#x5F97;&#x5230;&#x4E00;&#x4E9B;&#x526F;&#x4EA7;&#x54C1;&#xFF0C;&#x4E3B;&#x8981;&#x662F;&#x6E38;&#x620F;&#x4F18;&#x60E0;&#x5238;&#xFF0C;&#x8D44;&#x6599;&#x9875;&#x80CC;&#x666F;&#x548C;&#x8868;&#x60C5;&#x3002;&#x6211;&#x7684;&#x5EFA;&#x8BAE;&#x662F;&#xFF0C;&#x4F18;&#x60E0;&#x5238;&#x5982;&#x679C;&#x6709;&#x6298;&#x6263;&#x529B;&#x5EA6;&#x5F88;&#x5927;&#xFF0C;&#x6298;&#x5B8C;&#x4E00;&#x4E24;&#x5757;&#x94B1;&#x7684;&#xFF0C;&#x53EF;&#x4EE5;&#x4E70;&#x6765;&#x7EE7;&#x7EED;&#x6302;&#x5361;&#xFF0C;&#x8D44;&#x6599;&#x9875;&#x80CC;&#x666F;&#xFF0C;&#x597D;&#x770B;&#x7684;&#x81EA;&#x5DF1;&#x7559;&#x7740;&#xFF0C;&#x4E0D;&#x597D;&#x770B;&#x7684;&#x76F4;&#x63A5;&#x5206;&#x89E3;&#x6210;&#x5B9D;&#x73E0;&#xFF0C;&#x8868;&#x60C5;&#x4E00;&#x5F8B;&#x5206;&#x89E3;&#x6210;&#x5B9D;&#x73E0;&#x3002;&#x5B9D;&#x73E0;&#x53EF;&#x4EE5;&#x62FF;&#x6765;&#x505A;&#x8865;&#x5145;&#x5305;&#xFF0C;&#x8865;&#x5145;&#x5305;&#x53EF;&#x4EE5;&#x5356;&#x6389;&#x6216;&#x8005;&#x81EA;&#x5DF1;&#x5F00;&#x95EA;&#x5361;&#x3002;<br>
<img src="https://raw.githubusercontent.com/Shunix/BlogImages/master/20170423_steam_coupon.png" alt="&#x4F18;&#x60E0;&#x5238;" loading="lazy"><br>
<img src="https://raw.githubusercontent.com/Shunix/BlogImages/master/20170423_steam_background.png" alt="&#x80CC;&#x666F;" loading="lazy"></li>
</ol>
<h4 id>&#x5173;&#x4E8E;&#x6302;&#x5361;</h4>
<p>&#x4E4B;&#x524D;&#x6709;&#x8BF4;&#x5230;&#x8FC7;&#xFF0C;&#x96C6;&#x6362;&#x5F0F;&#x5361;&#x724C;&#x662F;&#x9700;&#x8981;&#x4E00;&#x5B9A;&#x7684;&#x6E38;&#x620F;&#x65F6;&#x95F4;&#x624D;&#x80FD;&#x6389;&#x843D;&#x7684;&#xFF0C;&#x4E70;&#x4E86;&#x90A3;&#x4E48;&#x591A;&#x559C;&#x52A0;&#x4E00;&#xFF0C;&#x4E0D;&#x53EF;&#x80FD;&#x771F;&#x7684;&#x90FD;&#x81EA;&#x5DF1;&#x73A9;&#x591F;&#x65F6;&#x5E38;&#x5427;&#x3002;&#x8FD9;&#x4E2A;&#x65F6;&#x5019;&#xFF0C;&#x5C31;&#x9700;&#x8981;&#x4E00;&#x4E2A;&#x5F00;&#x6E90;&#x6302;&#x5361;&#x5DE5;&#x5177;&#xFF1A;<a href="https://github.com/JustArchi/ArchiSteamFarm">ASF</a>&#xFF0C;&#x8FD0;&#x884C;&#x9700;&#x8981;&#x6700;&#x65B0;&#x7248;&#x672C;&#x7684;.NET Framework&#x3002;&#x5728;&#x81EA;&#x5DF1;&#x7535;&#x8111;&#x4E0A;&#x6302;&#x592A;&#x9EBB;&#x70E6;&#x4E86;&#xFF0C;&#x63A8;&#x8350;&#x641E;&#x4E2A;Linux&#x7684;VPS&#xFF0C;&#x7136;&#x540E;&#x88C5;&#x4E2A;mono&#x5C31;&#x53EF;&#x4EE5;24&#x5C0F;&#x65F6;&#x6302;&#x5361;&#x4E86;&#x3002;&#x6559;&#x7A0B;&#x5728;<a href="https://github.com/JustArchi/ArchiSteamFarm/wiki/Mono">&#x8FD9;&#x91CC;</a>&#x3002;&#x5982;&#x679C;&#x9047;&#x5230;&#x9891;&#x7E41;&#x9700;&#x8981;&#x8F93;&#x5165;steam&#x4E8C;&#x6B21;&#x9A8C;&#x8BC1;&#x7801;&#x7684;&#x95EE;&#x9898;&#xFF0C;&#x53EF;&#x4EE5;&#x770B;&#x770B;<a href="https://github.com/JustArchi/ArchiSteamFarm/wiki/Escrow">&#x8FD9;&#x4E2A;</a>&#x3002;ASF&#x652F;&#x6301;&#x79BB;&#x7EBF;&#x6302;&#x673A;&#xFF0C;&#x8FD9;&#x4E00;&#x70B9;&#x8FD8;&#x662F;&#x975E;&#x5E38;&#x65B9;&#x4FBF;&#x7684;&#xFF0C;&#x53EF;&#x4EE5;&#x907F;&#x514D;&#x522B;&#x4EBA;&#x5728;&#x4F60;&#x6302;&#x673A;&#x7684;&#x65F6;&#x5019;&#x8BEF;&#x8BA4;&#x4E3A;&#x4F60;&#x5728;&#x7EBF;&#xFF0C;&#x5C0F;&#x7A97;&#x4E0D;&#x56DE;&#x7684;&#x8BEF;&#x4F1A;&#x3002;</p>
<h4 id>&#x7ED3;&#x8BED;</h4>
<p>&#x6700;&#x540E;&#x7ED9;&#x4E2A;&#x6211;&#x7684;&#x8D44;&#x6599;&#x9875;&#x94FE;&#x63A5;&#xFF0C;&#x6B22;&#x8FCE;&#x5927;&#x5BB6;&#x52A0;&#x597D;&#x53CB;&#x3002;<br>
<a href="https://steamcommunity.com/id/rayewang">https://steamcommunity.com/id/rayewang</a></p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[Blog Migration Notes]]></title><description><![CDATA[<!--kg-card-begin: markdown--><p>My SSL certificate expired at the end of last month. And I lost the private key of my EC2 instance by chance. As I didn&apos;t want renew the SSL certificate and my amazon account is running out of credit, I decide to migrate my blog to vultr. I</p>]]></description><link>https://shunix.com/blog-migration-notes/</link><guid isPermaLink="false">60812ae62b3f873b19511eba</guid><category><![CDATA[技术文章]]></category><dc:creator><![CDATA[Shunix]]></dc:creator><pubDate>Sun, 09 Apr 2017 13:09:18 GMT</pubDate><content:encoded><![CDATA[<!--kg-card-begin: markdown--><p>My SSL certificate expired at the end of last month. And I lost the private key of my EC2 instance by chance. As I didn&apos;t want renew the SSL certificate and my amazon account is running out of credit, I decide to migrate my blog to vultr. I keep a migration notes here, so the migration will be more efficient next time.</p>
<ul>
<li>Step 1: Back up blog data.<br>
As my blog is backed by Ghost, I exported blog data in its control panel and got a json file.</li>
<li>Step 2: Install nodejs and npm on new VPS.<br>
Install nodejs and npm with the package manager of your distribution. Take Ubuntu for example.<br>
<code>$ sudo apt-get install nodejs</code><br>
<code>$ sudo apt-get install npm</code><br>
On some versions of Debian/Ubuntu, nodejs-legacy package is required. It provides necessary symbolic links.<br>
<code>$ sudo apt-get install nodejs-legacy</code></li>
<li>Step 3: Install Ghost.<br>
Download Ghost and unzip it.<br>
<code>$ curl -L https://ghost.org/zip/ghost-latest.zip -o ghost.zip</code><br>
<code>$ unzip -uo ghost.zip -d /var/www/ghost</code><br>
Now install dependency for Ghost.<br>
<code>$ cd /var/www/ghost &amp;&amp; npm install --production</code></li>
<li>Step 4: Configure Ghost.<br>
Create config.js.<br>
<code>$ cd /var/www/ghost &amp;&amp; cp config.example.js config.js</code><br>
Substitute domain name in production section with your own. If you don&apos;t need mail service, leave the mail brackets blank. If you do, Mailgun is recommended.</li>
<li>Step 5: Make Ghost run.<br>
<code>$ npm start --production</code> works fine surely. But if you log out from SSH, ghost will stop running. <strong>forever</strong> give us a way to run Ghost as a service.<br>
<code>$ npm install forever -g</code><br>
<code>$ NODE_ENV=production forever start index.js</code></li>
<li>Step 6: Obtain a SSL certificate.<br>
<strong>Let&apos;s Encrypt</strong> provides free SSL certificate. Detailed information can be found at <a href="https://letsencrypt.org/">https://letsencrypt.org/</a>.<br>
Since <strong>Let&apos;s Encrypt</strong> certificate only last for 90 days, I add a line to crontab to auto renew certificate.<br>
<code>0 6 * * 1 certbot renew</code></li>
<li>Step 7: Reverse proxy with nginx.<br>
By default, Ghost runs on port 2368. It&apos;s not recommend to run Ghost directly on port 80 for security concerns. We should run Ghost with a web server and proxy the access of port 80 to port 2368. I prefer nginx.<br>
Create a configuration file for ghost and create a symbolic link.<br>
<code>$ touch /etc/nginx/sites-available/ghost.conf</code><br>
<code>$ sudo ln -s /etc/nginx/sites-available/ghost.conf /etc/nginx/sites-enabled/ghost.conf</code><br>
Here&apos;s my ghost.conf, it contains SSL configuration.</li>
</ul>
<pre><code>server {
    listen 80;
    server_name shunix.com;

    location / {
        return 301 https://$server_name$request_uri;
    }
}

server {
    server_name www.shunix.com;
    return 301 $scheme://shunix.com$request_uri;
}

server {
     listen 443 ssl;
     server_name shunix.com;

     root /var/www/ghost;
     index index.html index.htm;
     client_max_body_size 10G;

     location / {
         proxy_pass http://localhost:2368;
         proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
         proxy_set_header Host $http_host;
         proxy_set_header X-Forwarded-Proto $scheme;
         proxy_buffering off;
     }
     ssl on;
     ssl_certificate /etc/letsencrypt/live/shunix.com/fullchain.pem;
     ssl_certificate_key /etc/letsencrypt/live/shunix.com/privkey.pem;
     ssl_prefer_server_ciphers On;
     ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
     ssl_ciphers ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:DH+AES:ECDH+3DES:DH+3DES:RSA+AESGCM:RSA+AES:RSA+3DES:!aNULL:!MD5:!DSS;
 }

</code></pre>
<ul>
<li>Step 8: Change A record to point to new IP address.</li>
<li>Step 9: Setup account and import data.</li>
</ul>
<p>Till now, we have complete the migration, the new blog should be online.</p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[Activity Leak Detection]]></title><description><![CDATA[<!--kg-card-begin: markdown--><h4 id="priorknowledge">Prior Knowledge</h4>
<h6 id="referenceandreferencequeue">Reference and ReferenceQueue</h6>
<p>Begin with Java 1.2, the <strong>java.lang.ref</strong> package give us limited degree of interaction with garbage collector. The subclasses of <strong>Reference</strong> and <strong>ReferenceQueue</strong> are quite useful if we wanna do something with garbage collection.<br>
The constructor of <strong>Reference</strong> takes a referent and a</p>]]></description><link>https://shunix.com/activity-leak-detection/</link><guid isPermaLink="false">60812ae62b3f873b19511eb6</guid><category><![CDATA[技术文章]]></category><dc:creator><![CDATA[Shunix]]></dc:creator><pubDate>Tue, 17 Jan 2017 13:20:23 GMT</pubDate><content:encoded><![CDATA[<!--kg-card-begin: markdown--><h4 id="priorknowledge">Prior Knowledge</h4>
<h6 id="referenceandreferencequeue">Reference and ReferenceQueue</h6>
<p>Begin with Java 1.2, the <strong>java.lang.ref</strong> package give us limited degree of interaction with garbage collector. The subclasses of <strong>Reference</strong> and <strong>ReferenceQueue</strong> are quite useful if we wanna do something with garbage collection.<br>
The constructor of <strong>Reference</strong> takes a referent and a <strong>ReferenceQueue</strong> as parameters.</p>
<pre><code class="language-java">Reference(T r, ReferenceQueue&lt;? super T&gt; q) {
    referent = r;
    queue = q;
}
</code></pre>
<p>We can regard <strong>ReferenceQueue</strong> as a callback of garbage collector. At some point, garbage collector will enqueue the reference. For different reference types, the time is different.<br>
Three different type of references exist, each being weaker than the preceding one: <strong>SoftReference</strong>, <strong>WeakReference</strong> and <strong>PhantomReference</strong>. &quot;Weakness&quot; here means that less restrictions are being imposed on the garbage collector as to when it is allowed to actually garbage-collect the referenced object.<br>
Garbage collector will not clear the referent of <strong>SoftReference</strong> until the runtime must reclaim memory to satisfy an allocation. But it&apos;s not recommended using it for caching as it&apos;s inefficient.<br>
<strong>WeakReference</strong> is commonly used for &quot;canonical mappings&quot;. <strong>WeakHashMap</strong> is a typical case. Unlike <strong>SoftReference</strong>, <strong>WeakReference</strong> will be cleared and enqueued as soon as is known to be weakly-referenced.<br>
<strong>PhantomReference</strong> is a better alternative for <em>finalize()</em> method. As <em>finalize()</em> has performance problem and is unpredictable, we can use <strong>PhantomReference</strong> to do some pre-mortem cleanup.<br>
For both <strong>SoftReference</strong> and <strong>WeakReference</strong>, the referent will be nullified before enqueued. And the garbage collector will finalize these referent at some future time.<br>
As for <strong>PhantomReference</strong>, garbage collector will finish the finalization of referent and then enqueue the reference, but it will not nullify the referent. Thus <strong>PhantomReference</strong> must be used together with a valid reference queue, otherwise it&apos;s useless. And we have to clear the reference queue manually, if not, memory of the referent cannot be reclaimed by garbage collector.</p>
<h4 id="activityleakdetection">Activity Leak Detection</h4>
<h6 id="howtodefineactivityleak">How to Define Activity Leak?</h6>
<p>In brief, if an activity has run over its <em>onDestroy()</em> method but garbage collector cannot reclaim its memory, the activity is leaked.</p>
<h6 id="activitydiagram">Activity Diagram</h6>
<p>I made a activity diagram to demonstrate how to detect an activity leak in Android.</p>
<ol>
<li>Register life cycle callback by <em>void registerActivityLifecycleCallbacks (Application.ActivityLifecycleCallbacks callback)</em>.</li>
<li>On every activity&apos;s <em>onDestroy()</em> callback, create a <strong>WeakReference</strong> of it with a non-null <strong>ReferenceQueue</strong>.</li>
<li>Force the VM do a garbage collection.</li>
<li>Check the reference queue, if the reference we created before has not been enqueued, it&apos;s very likely that it leaks.<br>
<img src="https://raw.githubusercontent.com/Shunix/BlogImages/master/20170117_activity_leak_detection.png" alt="ActivityLeakDetection" loading="lazy"></li>
</ol>
<h6 id="furtherexplaination">Further Explaination</h6>
<ol>
<li><em>void registerActivityLifecycleCallbacks (Application.ActivityLifecycleCallbacks callback)</em> only supports Android API level 14 and above. If you need compatibility for API level below 14, you can substitute <em>mInstrumentation</em> in <strong>ActivityThread</strong> with your own implementation. It&apos;s not hard to do with reflection. But on some few third-party ROM which modified the <em>ActivityThread.java</em>, this method does not work. As <strong>ActivityThread</strong> is not in public API, this method doesn&apos;t guarantee to work on future Android versions.</li>
<li>Actually, there&apos;s no way to force the VM do garbage collection. We can only suggest the VM to do a garbage collection, but we can&apos;t guarantee it really did. That&apos;s why I said it is just very likely that the activity leaks if its reference is not enqueued after a forced garbage collection. There will be a few false positives due to Java garbage collector&apos;s behavior.<br>
Here&apos;s code taken from Android Finalization Tester:<pre><code>public static void induceFinalization() {
    System.gc();
    enqueueReferences();
    System.runFinalization();
}
</code></pre>
</li>
<li>We can&apos;t check reference queue immediately, as garbage collector need time to enqueue references, but we don&apos;t have a programmatic way to determine the time, we can only use an empirical value. Here&apos;s the implementation of <em>enqueueReferences()</em>:<pre><code>public static void enqueueReferences() {
    /*
     * Hack. We don&apos;t have a programmatic way to wait for the       reference queue
     * daemon to move references to the appropriate queues.
     */
    try {
        Thread.sleep(100);
    } catch (InterruptedException e) {
        throw new AssertionError();
    }
}
</code></pre>
</li>
</ol>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[Efficient Thread-safe Singleton in Java]]></title><description><![CDATA[<!--kg-card-begin: markdown--><h4 id="singlethreadedversion">Single-threaded Version</h4>
<pre><code class="language-java">class Foo {
    private static Helper helper;
    public static Helper getHelper() {
        if (helper == null) {
            helper = new Helper();
        }
        return helper;
    }
}
</code></pre>
<p>The code works fine in single thread case. If multiple threads access <strong>getHelper()</strong> method simultaneously, they may try to create multiple objects or some of them may get an incompletely</p>]]></description><link>https://shunix.com/efficient-thread-safe-singleton-in-java/</link><guid isPermaLink="false">60812ae62b3f873b19511eb8</guid><category><![CDATA[技术文章]]></category><dc:creator><![CDATA[Shunix]]></dc:creator><pubDate>Wed, 21 Dec 2016 12:16:40 GMT</pubDate><content:encoded><![CDATA[<!--kg-card-begin: markdown--><h4 id="singlethreadedversion">Single-threaded Version</h4>
<pre><code class="language-java">class Foo {
    private static Helper helper;
    public static Helper getHelper() {
        if (helper == null) {
            helper = new Helper();
        }
        return helper;
    }
}
</code></pre>
<p>The code works fine in single thread case. If multiple threads access <strong>getHelper()</strong> method simultaneously, they may try to create multiple objects or some of them may get an incompletely initialized object.</p>
<h4 id="naivethreadsafeversion">Naive Thread-safe Version</h4>
<pre><code class="language-java">class Foo {
    private static Helper helper;
    public synchronized static Helper getHelper() {
        if (helper == null) {
            helper = new Helper();
        }
        return helper;
    }
}
</code></pre>
<p>The code is thread-safe, but synchronize the whole <strong>getHelper()</strong> method is unnecessary. Actually, only when multiple threads try to initialize <strong>helper</strong>, synchronization is needed. After <strong>helper</strong> initialized, simultaneous access to <strong>getHelper()</strong> works correctly without synchronization. It should return the same object.</p>
<h4 id="doublecheckedlockingversion">Double-checked Locking Version</h4>
<pre><code class="language-java">class Foo {
    private static volatile Helper helper;
    public static Helper getHelper() {
        Helper result = helper;
        if (result == null) {
            synchronized(Foo.class) {
                result = helper;
                if (result == null) {
                    result = new Helper();
                    helper = result;
                }
            }
        }
        return result;
    }
}
</code></pre>
<p>We optimized <strong>getHelper()</strong> method in the following manner:</p>
<ol>
<li>Check if <strong>helper</strong> is initialized, if so, return it immediately.</li>
<li>Obtain lock.</li>
<li>Double-check if <strong>helper</strong> is initialized, other thread may have already initialized it.</li>
<li>Initialize <strong>helper</strong>.</li>
</ol>
<p>The <strong>volatile</strong> keyword is necessary here. Prior to JDK 1.5, the compiler may reorder instructions. As a result, there&apos;s no way to guarantee an object&apos;s fields are all initialized before it&apos;s visible to other thread. Other thread may hold a reference to an incompletely initialized object, which may cause crashes.<br>
Since JDK 1.5, <strong>volatile</strong> provide <strong>Happened-before</strong> guarantee, it make sure of these two things:</p>
<ol>
<li>If Thread A writes to a volatile variable and Thread B subsequently reads the same volatile variable, then all variables visible to Thread A before writing the volatile variable, will also be visible to Thread B after it has read the volatile variable.</li>
<li>The reading and writing instructions of volatile variables cannot be reordered by the JVM.</li>
</ol>
<p>There&apos;s no chance a thread see an incompletely initialized object. Double-checked locking idiom only works on JDK 1.5 or later. And it requires good understanding of java memory model.<br>
Local variable <strong>result</strong> here slightly optimized the performance. Accessing volatile variable requires the variable to be read or written to main memory rather than CPU cache. If <strong>helper</strong> is already initialized, we only access volatile variable once due to &quot;return result&quot; instead of &quot;return helper&quot;.</p>
<h4 id="initializationondemandversion">Initialization-on-demand Version</h4>
<pre><code class="language-java">class Foo {
    private Foo() {
    
    }
    private static class FooHolder {
        private static final Foo INSTANCE = new Foo();
    }
    public static Foo getInstance() {
        return FooHolder.INSTANCE;
    }
}
</code></pre>
<p>Java Language Specification specified that the static class <strong>FooHolder</strong> is not initialized until the JVM determines it must be executed. Until <strong>getInstance()</strong> gets called, <strong>INSTANCE</strong> will not be initialized. Since the class initialization phase is guaranteed by the JLS to be serial, no further synchronization is required.</p>
<h4 id="enumversion">Enum Version</h4>
<pre><code class="language-java">enum Foo {
    INSTANCE;
}
</code></pre>
<p>Implementing singleton with enum is recommended by <em><strong>Effective Java</strong></em>. Creation of enum is thread-safe, it&apos;s guaranteed by JVM. Compared with other implementation, enum version has unique advantages:</p>
<ol>
<li>It prevents creating another instance via reflection, although you can work around this in previous version by throwing exception in private constructor.</li>
<li>If you&apos;re dealing with a serializable singleton, as deserialization will always create a new instance, you have to discard it by implementing <strong>readResolve()</strong> method and handling singleton state carefully. But with enum singleton, serialization and deserialization is guaranteed by JVM.</li>
</ol>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[Avoid Memory Leaks in Android]]></title><description><![CDATA[<!--kg-card-begin: markdown--><p>Java is a garbage-collecting-language, the garbage collector deals with memory properly on most cases. But we may still encounter memory leaks due to some logical bugs. I&apos;ll list some common cases that cause memory leaks in Android.</p>
<h4 id="staticreference">Static Reference</h4>
<p>I just take static reference to activity for example.</p>]]></description><link>https://shunix.com/avoid-memory-leaks-in-android/</link><guid isPermaLink="false">60812ae62b3f873b19511eb5</guid><category><![CDATA[技术文章]]></category><dc:creator><![CDATA[Shunix]]></dc:creator><pubDate>Thu, 08 Dec 2016 12:33:23 GMT</pubDate><content:encoded><![CDATA[<!--kg-card-begin: markdown--><p>Java is a garbage-collecting-language, the garbage collector deals with memory properly on most cases. But we may still encounter memory leaks due to some logical bugs. I&apos;ll list some common cases that cause memory leaks in Android.</p>
<h4 id="staticreference">Static Reference</h4>
<p>I just take static reference to activity for example. It&apos;s a typical case.<br>
If an activity&apos;s <strong>onDestroy()</strong> method gets called, garbage collector should be able to recycle it. But garbage collector cannot recycle an object if other GC root holds strong reference to it. I used to see code like this:</p>
<pre><code class="language-java">public class MyApplication extends Application {
    public static Activity sTopActivity;
}
</code></pre>
<p>The programmer intends to hold a static reference to the activity on top of the stack. If this reference doesn&apos;t get reassigned on every activity&apos;s <strong>onCreate()</strong> method, it may cause activity leaks. Extending activity&apos;s lifecycle is dangerous, if you find you have to it, reconsider your design.</p>
<h4 id="handler">Handler</h4>
<h6 id="idlehandler">IdleHandler</h6>
<pre><code class="language-java">/**
 * Callback interface for discovering when a thread is going to block
 * waiting for more messages.
 */
public static interface IdleHandler {
	/**
	 * Called when the message queue has run out of messages and will now
	 * wait for more.  Return true to keep your idle handler active, false
	 * to have it removed.  This may be called if there are still messages
	 * pending in the queue, but they are all scheduled to be dispatched
	 * after the current time.
	 */
	boolean queueIdle();
}
</code></pre>
<p>We may call this method to add IdleHandler to a message queue:</p>
<pre><code class="language-java">/**
 * Add a new {@link IdleHandler} to this message queue.  This may be
 * removed automatically for you by returning false from
 * {@link IdleHandler#queueIdle IdleHandler.queueIdle()} when it is
 * invoked, or explicitly removing it with {@link #removeIdleHandler}.
 * 
 * &lt;p&gt;This method is safe to call from any thread.
 * 
 * @param handler The IdleHandler to be added.
 */
public void addIdleHandler(IdleHandler handler) {
	if (handler == null) {
		throw new NullPointerException(&quot;Can&apos;t add a null IdleHandler&quot;);
	}
	synchronized (this) {
		mIdleHandlers.add(handler);
	}
}
</code></pre>
<p>If we didn&apos;t remove idle handler manually, <strong>Looper.loop()</strong> will keep running, <em><strong>mIdleHandlers</strong></em> holds reference to idle handler we added before, the idle handler may hold reference to the activity if it&apos;s a non-static inner class, thus cause activity leaks.<br>
So make sure to remove idle handler on activity&apos;s <strong>onDestroy()</strong> callback.</p>
<h6 id="delayedmessage">Delayed Message</h6>
<p>If we post a message or runnable with <strong>sendMessageDelayed(Message msg, long delayMillis)</strong> or <strong>postDelayed(Runnable r, long delayMillis)</strong>, there&apos;s a chance that these messages haven&apos;t been handled yet when the activity finished. Messages in message queue hold reference to handlers, handlers may referencing activity if it&apos;s a non-static inner class.<br>
Remove all messages in <strong>onDestroy()</strong> or make the handler class static can both avoid activity leaks.</p>
<h4 id="threadandasynctask">Thread and AsyncTask</h4>
<p>Life cycle of a thread is unpredictable, it&apos;s very likely that threads created in activity haven&apos;t finished execution after activity&apos;s <strong>onDestroy()</strong> get called. Thread and AsyncTask holds reference to activity if it&apos;s a non-static inner class. Activity cannot be recycled before worker thread finish execution.<br>
To solve this problem, we made these inner class static. If static inner class needs access to activity&apos;s member field, create a <strong>WeakReference</strong> inside the static inner class, it won&apos;t prevent garbage collector from recycling the activity.</p>
<h4 id="webview">WebView</h4>
<p>Before Android Honeycomb, there&apos;s a disgusting bug with <strong>WebView</strong>, if the context passed to webview is activity&apos;s context, this activity can&apos;t be recycled, if it&apos;s application&apos;s context, this webview can&apos;t show dialog and start other activity.<br>
To work around this problem, we usually start webview in a separate process. Once the webview finish its work, we kill the process to avoid memory leak. If the webview process need to exchange data with main process, we need to implement some <strong>AIDL</strong> interface.</p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[Monitor Android Looper]]></title><description><![CDATA[<!--kg-card-begin: markdown--><p>As I write in the previous post <a href="https://shunix.com/android-message-handling-mechanism/">Android Message Handling Mechanism</a>, all messages dispatched to main thread will be handled in the looper of main thread. If a message cost a long time, Android will report an ANR. It&apos;s necessary for a monitor library to detect ANR, so</p>]]></description><link>https://shunix.com/monitor-android-looper/</link><guid isPermaLink="false">60812ae62b3f873b19511eb4</guid><category><![CDATA[技术文章]]></category><dc:creator><![CDATA[Shunix]]></dc:creator><pubDate>Fri, 02 Dec 2016 10:01:25 GMT</pubDate><content:encoded><![CDATA[<!--kg-card-begin: markdown--><p>As I write in the previous post <a href="https://shunix.com/android-message-handling-mechanism/">Android Message Handling Mechanism</a>, all messages dispatched to main thread will be handled in the looper of main thread. If a message cost a long time, Android will report an ANR. It&apos;s necessary for a monitor library to detect ANR, so I need to log time costs for handling each message and report when the time reaches a threshold.<br>
Let&apos;s begin with the code of <strong>Looper.loop()</strong>:</p>
<pre><code class="language-java">public static void loop() {  
    final Looper me = myLooper();
    if (me == null) {
        throw new RuntimeException(&quot;No Looper; Looper.prepare() wasn&apos;t called on this thread.&quot;);
    }
    final MessageQueue queue = me.mQueue;

    // Make sure the identity of this thread is that of the local process,
    // and keep track of what that identity token actually is.
    Binder.clearCallingIdentity();
    final long ident = Binder.clearCallingIdentity();

    for (;;) {
        Message msg = queue.next(); // might block
        if (msg == null) {
            // No message indicates that the message queue is quitting.
            return;
        }

        // This must be in a local variable, in case a UI event sets the logger
        Printer logging = me.mLogging;
        if (logging != null) {
            logging.println(&quot;&gt;&gt;&gt;&gt;&gt; Dispatching to &quot; + msg.target + &quot; &quot; +
                    msg.callback + &quot;: &quot; + msg.what);
        }

        msg.target.dispatchMessage(msg);

        if (logging != null) {
            logging.println(&quot;&lt;&lt;&lt;&lt;&lt; Finished to &quot; + msg.target + &quot; &quot; + msg.callback);
        }

        // Make sure that during the course of dispatching the
        // identity of the thread wasn&apos;t corrupted.
        final long newIdent = Binder.clearCallingIdentity();
        if (ident != newIdent) {
            Log.wtf(TAG, &quot;Thread identity changed from 0x&quot;
                    + Long.toHexString(ident) + &quot; to 0x&quot;
                    + Long.toHexString(newIdent) + &quot; while dispatching to &quot;
                    + msg.target.getClass().getName() + &quot; &quot;
                    + msg.callback + &quot; what=&quot; + msg.what);
        }

        msg.recycle();
    }
}
</code></pre>
<p>Obviously, we only need to care about the execution time of <strong>msg.target.dispatchMessage(msg)</strong>. I was thinking about hook <strong>Handler.dispatchMessage(Message msg)</strong> via Xposed, but Xposed works on class-level, I&apos;ll get the execution time of all handler instance. Actually, I just wanna monitor the message handling time of main looper. So can we do it with a lighter way?<br>
Look at these lines:</p>
<pre><code class="language-java">Printer logging = me.mLogging;
if (logging != null) {
    logging.println(&quot;&gt;&gt;&gt;&gt;&gt; Dispatching to &quot; + msg.target + &quot; &quot; +
            msg.callback + &quot;: &quot; + msg.what);
}

msg.target.dispatchMessage(msg);

if (logging != null) {
    logging.println(&quot;&lt;&lt;&lt;&lt;&lt; Finished to &quot; + msg.target + &quot; &quot; + msg.callback);
}
</code></pre>
<p>Looper will print logs before and after handling message. We can consider the time difference as message handling time cost. All we need to do, is replace the <strong>mLogging</strong> with a customized printer. I write a monitor class to do this work:</p>
<pre><code class="language-java">package com.shunix.droidsentry.monitor;

import android.os.Looper;
import android.util.Printer;

/**
 * @author rayewang
 * @since 2016/11/23
 */
public class LooperMonitor {
    private final static int INTERVAL_THRESHOLD = 50;

    private static ThreadLocal&lt;LooperMonitor&gt; sInstance = new ThreadLocal&lt;LooperMonitor&gt;();

    public static void monitor() {
        if (sInstance.get() != null) {
            throw new RuntimeException(&quot;One looper can only be monitored once!&quot;);
        }
        Looper myLooper = Looper.myLooper();
        if (myLooper == null) {
            throw new IllegalStateException(&quot;The current thread must have a looper!&quot;);
        }
        sInstance.set(new LooperMonitor());
        myLooper.setMessageLogging(new LooperPrinter(myLooper));
    }

    static class LooperPrinter implements Printer {
        private final static String START_TAG = &quot;&gt;&gt;&gt;&gt;&gt; Dispatching to &quot;;
        private final static String END_TAG = &quot;&lt;&lt;&lt;&lt;&lt; Finished to &quot;;

        private Looper mLooper;
        private long mStartTime;
        private long mEndTime;

        public LooperPrinter(Looper looper) {
            mLooper = looper;
        }

        @Override
        public void println(String s) {
            if (s.startsWith(START_TAG)) {
                mStartTime = System.currentTimeMillis();
            } else if (s.startsWith(END_TAG)) {
                mEndTime = System.currentTimeMillis();
                if (mStartTime != 0) {
                    long interval = mEndTime - mStartTime;
                    if (interval &gt; INTERVAL_THRESHOLD) {
                        // TODO report to server
                    }
                }
            }
        }
    }
}
</code></pre>
<p>To use this class, just call <strong>LooperMonitor.monitor()</strong>, this class will monitor the looper of calling thread automatically.</p>
<!--kg-card-end: markdown-->]]></content:encoded></item></channel></rss>