<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Hotaru</title><description>你现在，是什么颜色的呢？</description><link>https://006lp.de/</link><language>zh_CN</language><item><title>高等数学｜第0节 常用公式</title><link>https://006lp.de/posts/review-of-advanced-mathematics/0-common-formulas/</link><guid isPermaLink="true">https://006lp.de/posts/review-of-advanced-mathematics/0-common-formulas/</guid><description>高等数学常用公式汇总，涵盖基本求导公式、基本积分公式、常用等价无穷小、常用泰勒公式展开式，便于复习查阅。</description><pubDate>Mon, 03 Aug 2026 10:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;一、求导公式&lt;/h1&gt;
&lt;h2&gt;1、 基本初等函数求导公式&lt;/h2&gt;
&lt;h3&gt;(1). &lt;strong&gt;常数与幂函数&lt;/strong&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;$(C)&apos; = 0$&lt;/li&gt;
&lt;li&gt;$(x^\alpha)&apos; = \alpha x^{\alpha-1}$&lt;/li&gt;
&lt;li&gt;$(\sqrt{x})&apos; = \frac{1}{2\sqrt{x}}$&lt;/li&gt;
&lt;li&gt;$\left(\frac{1}{x}\right)&apos; = -\frac{1}{x^2}$&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;(2). &lt;strong&gt;指数与对数函数&lt;/strong&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;$(a^x)&apos; = a^x \ln a \quad (a &amp;gt; 0, a \neq 1)$&lt;/li&gt;
&lt;li&gt;$(e^x)&apos; = e^x$&lt;/li&gt;
&lt;li&gt;$(\log_a x)&apos; = \frac{1}{x \ln a} \quad (a &amp;gt; 0, a \neq 1)$&lt;/li&gt;
&lt;li&gt;$(\ln \vert{}x\vert{})&apos; = \frac{1}{x}$&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h2&gt;2、 三角函数与反三角函数求导&lt;/h2&gt;
&lt;h3&gt;(1). &lt;strong&gt;三角函数&lt;/strong&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;$(\sin x)&apos; = \cos x$&lt;/li&gt;
&lt;li&gt;$(\cos x)&apos; = -\sin x$&lt;/li&gt;
&lt;li&gt;$(\tan x)&apos; = \sec^2 x$&lt;/li&gt;
&lt;li&gt;$(\cot x)&apos; = -\csc^2 x$&lt;/li&gt;
&lt;li&gt;$(\sec x)&apos; = \sec x \tan x$&lt;/li&gt;
&lt;li&gt;$(\csc x)&apos; = -\csc x \cot x$&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;(2). &lt;strong&gt;反三角函数&lt;/strong&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;$(\arcsin x)&apos; = \frac{1}{\sqrt{1 - x^2}}$&lt;/li&gt;
&lt;li&gt;$(\arccos x)&apos; = -\frac{1}{\sqrt{1 - x^2}}$&lt;/li&gt;
&lt;li&gt;$(\arctan x)&apos; = \frac{1}{1 + x^2}$&lt;/li&gt;
&lt;li&gt;$(\text{arccot}, x)&apos; = -\frac{1}{1 + x^2}$&lt;/li&gt;
&lt;li&gt;$(\text{arcsec}, x)&apos; = \frac{1}{\vert{}x\vert{}\sqrt{x^2 - 1}}$&lt;/li&gt;
&lt;li&gt;$(\text{arccsc}, x)&apos; = -\frac{1}{\vert{}x\vert{}\sqrt{x^2 - 1}}$&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h2&gt;3、 双曲函数与反双曲函数求导（重点）&lt;/h2&gt;
&lt;h3&gt;(1). &lt;strong&gt;双曲函数&lt;/strong&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;双曲正弦：$(\sinh x)&apos; = \cosh x$&lt;/li&gt;
&lt;li&gt;双曲余弦：$(\cosh x)&apos; = \sinh x$&lt;/li&gt;
&lt;li&gt;双曲正切：$(\tanh x)&apos; = \text{sech}^2 x = 1 - \tanh^2 x$&lt;/li&gt;
&lt;li&gt;双曲余切：$(\coth x)&apos; = -\text{csch}^2 x = 1 - \coth^2 x$&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;(2). &lt;strong&gt;反双曲函数&lt;/strong&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;反双曲正弦：$(\text{arsinh}, x)&apos; = \left(\ln(x + \sqrt{x^2 + 1})\right)&apos; = \frac{1}{\sqrt{x^2 + 1}}$&lt;/li&gt;
&lt;li&gt;反双曲余弦：$(\text{arcosh}, x)&apos; = \left(\ln(x + \sqrt{x^2 - 1})\right)&apos; = \frac{1}{\sqrt{x^2 - 1}} \quad (x &amp;gt; 1)$&lt;/li&gt;
&lt;li&gt;反双曲正切：$(\text{artanh}, x)&apos; = \left(\frac{1}{2}\ln \frac{1+x}{1-x}\right)&apos; = \frac{1}{1 - x^2} \quad (\vert{}x\vert{} &amp;lt; 1)$&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h2&gt;4、 基本运算法则&lt;/h2&gt;
&lt;h3&gt;(1). &lt;strong&gt;四则运算&lt;/strong&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;$(u \pm v)&apos; = u&apos; \pm v&apos;$&lt;/li&gt;
&lt;li&gt;$(uv)&apos; = u&apos;v + uv&apos;$&lt;/li&gt;
&lt;li&gt;$\left(\frac{u}{v}\right)&apos; = \frac{u&apos;v - uv&apos;}{v^2} \quad (v \neq 0)$&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;(2). &lt;strong&gt;复合函数（链式法则）&lt;/strong&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;$\frac{dy}{dx} = \frac{dy}{du} \cdot \frac{du}{dx}$&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;(3). &lt;strong&gt;反函数求导&lt;/strong&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;$f&apos;(x) = \frac{1}{(f^{-1})&apos;(y)} \quad (y = f(x))$&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;(4). &lt;strong&gt;幂指函数求导&lt;/strong&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;若 $y = u(x)^{v(x)} = e^{v(x) \ln u(x)}$，则：&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;$$y&apos; = u(x)^{v(x)} \left( v&apos;(x) \ln u(x) + \frac{v(x) u&apos;(x)}{u(x)} \right)$$&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;5、 常用 $n$ 阶高阶导数公式与莱布尼茨公式&lt;/h2&gt;
&lt;h3&gt;(1). &lt;strong&gt;基本函数的 $n$ 阶导数&lt;/strong&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;$(x^m)^{(n)} = P_m^n x^{m-n} = \frac{m!}{(m-n)!} x^{m-n} \quad (n \le m)$；若 $n &amp;gt; m$ 则为 $0$&lt;/li&gt;
&lt;li&gt;$\left(\frac{1}{ax + b}\right)^{(n)} = \frac{(-1)^n n! a^n}{(ax + b)^{n+1}}$&lt;/li&gt;
&lt;li&gt;$(\ln(ax + b))^{(n)} = \frac{(-1)^{n-1} (n-1)! a^n}{(ax + b)^n}$&lt;/li&gt;
&lt;li&gt;$(e^{ax})^{(n)} = a^n e^{ax}$&lt;/li&gt;
&lt;li&gt;$(a^x)^{(n)} = a^x (\ln a)^n$&lt;/li&gt;
&lt;li&gt;$(\sin(ax + b))^{(n)} = a^n \sin\left(ax + b + \frac{n\pi}{2}\right)$&lt;/li&gt;
&lt;li&gt;$(\cos(ax + b))^{(n)} = a^n \cos\left(ax + b + \frac{n\pi}{2}\right)$&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;(2). &lt;strong&gt;莱布尼茨乘积求导公式 (Leibniz Rule)&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;若 $u(x), v(x)$ 均 $n$ 阶可导，则：&lt;/p&gt;
&lt;p&gt;$$(uv)^{(n)} = \sum_{k=0}^{n} C_n^k u^{(n-k)} v^{(k)} = \sum_{k=0}^{n} \binom{n}{k} u^{(n-k)} v^{(k)}$$&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;6、 特殊形式函数的求导公式&lt;/h2&gt;
&lt;h3&gt;(1). &lt;strong&gt;变限积分求导（含参变量积分）&lt;/strong&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;一般形式（含被积函数内参数 $x$）：&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;$$\frac{d}{dx} \int_{\phi(x)}^{\psi(x)} f(t, x) , dt = f(\psi(x), x)\psi&apos;(x) - f(\phi(x), x)\phi&apos;(x) + \int_{\phi(x)}^{\psi(x)} \frac{\partial f(t, x)}{\partial x} , dt$$&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;无内参形式：&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;$$\frac{d}{dx} \int_{\phi(x)}^{\psi(x)} f(t) , dt = f(\psi(x))\psi&apos;(x) - f(\phi(x))\phi&apos;(x)$$&lt;/p&gt;
&lt;h3&gt;(2). &lt;strong&gt;参数方程求导&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;设 $\begin{cases} x = \phi(t) \ y = \psi(t) \end{cases}$，且 $\phi&apos;(t) \neq 0$：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;一阶导数：$\frac{dy}{dx} = \frac{\psi&apos;(t)}{\phi&apos;(t)}$&lt;/li&gt;
&lt;li&gt;二阶导数：$\frac{d^2 y}{dx^2} = \frac{\frac{d}{dt}\left(\frac{dy}{dx}\right)}{\phi&apos;(t)} = \frac{\psi&apos;&apos;(t)\phi&apos;(t) - \psi&apos;(t)\phi&apos;&apos;(t)}{[\phi&apos;(t)]^3}$&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;(3). &lt;strong&gt;隐函数求导&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;由方程 $F(x, y) = 0$ 确定 $y = y(x)$，且 $F_y \neq 0$：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;一阶导数：$\frac{dy}{dx} = -\frac{F_x}{F_y}$&lt;/li&gt;
&lt;li&gt;二阶导数：$\frac{d^2 y}{dx^2} = -\frac{F_{xx} F_y^2 - 2 F_{xy} F_x F_y + F_{yy} F_x^2}{F_y^3}$&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h1&gt;二、积分公式&lt;/h1&gt;
&lt;h2&gt;1、 基本初等函数积分表&lt;/h2&gt;
&lt;h3&gt;(1). &lt;strong&gt;幂函数与指数函数&lt;/strong&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;$\int x^\mu , dx = \frac{x^{\mu+1}}{\mu+1} + C \quad (\mu \neq -1)$&lt;/li&gt;
&lt;li&gt;$\int \frac{1}{x} , dx = \ln \vert{}x\vert{} + C$&lt;/li&gt;
&lt;li&gt;$\int e^x , dx = e^x + C$&lt;/li&gt;
&lt;li&gt;$\int a^x , dx = \frac{a^x}{\ln a} + C \quad (a &amp;gt; 0, a \neq 1)$&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;(2). &lt;strong&gt;基本三角函数&lt;/strong&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;$\int \sin x , dx = -\cos x + C$&lt;/li&gt;
&lt;li&gt;$\int \cos x , dx = \sin x + C$&lt;/li&gt;
&lt;li&gt;$\int \tan x , dx = -\ln \vert{}\cos x\vert{} + C = \ln \vert{}\sec x\vert{} + C$&lt;/li&gt;
&lt;li&gt;$\int \cot x , dx = \ln \vert{}\sin x\vert{} + C$&lt;/li&gt;
&lt;li&gt;$\int \sec x , dx = \ln \vert{}\sec x + \tan x\vert{} + C = \ln \left\vert{} \tan\left( \frac{x}{2} + \frac{\pi}{4} \right) \right\vert{} + C$&lt;/li&gt;
&lt;li&gt;$\int \csc x , dx = \ln \vert{}\csc x - \cot x\vert{} + C = \ln \left\vert{} \tan \frac{x}{2} \right\vert{} + C$&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;(3). &lt;strong&gt;平方类与相乘类三角函数&lt;/strong&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;$\int \sec^2 x , dx = \tan x + C$&lt;/li&gt;
&lt;li&gt;$\int \csc^2 x , dx = -\cot x + C$&lt;/li&gt;
&lt;li&gt;$\int \sec x \tan x , dx = \sec x + C$&lt;/li&gt;
&lt;li&gt;$\int \csc x \cot x , dx = -\csc x + C$&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;(4). &lt;strong&gt;双曲函数&lt;/strong&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;$\int \sinh x , dx = \cosh x + C$&lt;/li&gt;
&lt;li&gt;$\int \cosh x , dx = \sinh x + C$&lt;/li&gt;
&lt;li&gt;$\int \text{sech}^2 x , dx = \tanh x + C$&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h2&gt;2、 含有 $a^2 \pm x^2$ 与 $\sqrt{a^2 \pm x^2}$ 的拓展公式（高频）&lt;/h2&gt;
&lt;h3&gt;(1). &lt;strong&gt;无理/有理二次分式&lt;/strong&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;$\int \frac{1}{a^2 + x^2} , dx = \frac{1}{a} \arctan \frac{x}{a} + C$&lt;/li&gt;
&lt;li&gt;$\int \frac{1}{a^2 - x^2} , dx = \frac{1}{2a} \ln \left\vert{} \frac{a+x}{a-x} \right\vert{} + C$&lt;/li&gt;
&lt;li&gt;$\int \frac{1}{x^2 - a^2} , dx = \frac{1}{2a} \ln \left\vert{} \frac{x-a}{x+a} \right\vert{} + C$&lt;/li&gt;
&lt;li&gt;$\int \frac{1}{\sqrt{a^2 - x^2}} , dx = \arcsin \frac{x}{a} + C$&lt;/li&gt;
&lt;li&gt;$\int \frac{1}{\sqrt{x^2 + a^2}} , dx = \ln(x + \sqrt{x^2 + a^2}) + C = \text{arsinh} \frac{x}{a} + C_1$&lt;/li&gt;
&lt;li&gt;$\int \frac{1}{\sqrt{x^2 - a^2}} , dx = \ln \vert{}x + \sqrt{x^2 - a^2}\vert{} + C$&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;(2). &lt;strong&gt;二次根式分子型（三元组合）&lt;/strong&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;$\int \sqrt{a^2 - x^2} , dx = \frac{x}{2}\sqrt{a^2 - x^2} + \frac{a^2}{2}\arcsin \frac{x}{a} + C$&lt;/li&gt;
&lt;li&gt;$\int \sqrt{x^2 + a^2} , dx = \frac{x}{2}\sqrt{x^2 + a^2} + \frac{a^2}{2}\ln(x + \sqrt{x^2 + a^2}) + C$&lt;/li&gt;
&lt;li&gt;$\int \sqrt{x^2 - a^2} , dx = \frac{x}{2}\sqrt{x^2 - a^2} - \frac{a^2}{2}\ln\vert{}x + \sqrt{x^2 - a^2}\vert{} + C$&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h2&gt;3、 指数与三角乘积积分&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;$\int e^{ax} \sin(bx) , dx = \frac{e^{ax}}{a^2 + b^2} (a\sin bx - b\cos bx) + C$&lt;/li&gt;
&lt;li&gt;$\int e^{ax} \cos(bx) , dx = \frac{e^{ax}}{a^2 + b^2} (a\cos bx + b\sin bx) + C$&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h2&gt;4、 常用递推与高阶三角定积分&lt;/h2&gt;
&lt;h3&gt;(1). &lt;strong&gt;华里斯公式（Wallis 公式 / 点火公式）&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;$$I_n = \int_0^{\frac{\pi}{2}} \sin^n x , dx = \int_0^{\frac{\pi}{2}} \cos^n x , dx = \begin{cases} \frac{n-1}{n} \cdot \frac{n-3}{n-2} \cdots \frac{1}{2} \cdot \frac{\pi}{2}, &amp;amp; n \text{ 为正偶数} \ \frac{n-1}{n} \cdot \frac{n-3}{n-2} \cdots \frac{2}{3} \cdot 1, &amp;amp; n \text{ 为正奇数} \end{cases}$$&lt;/p&gt;
&lt;h3&gt;(2). &lt;strong&gt;常用递推关系&lt;/strong&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;$\int \tan^n x , dx = \frac{\tan^{n-1} x}{n-1} - \int \tan^{n-2} x , dx \quad (n \ge 2)$&lt;/li&gt;
&lt;li&gt;$\int \sec^n x , dx = \frac{1}{n-1} \sec^{n-2} x \tan x + \frac{n-2}{n-1} \int \sec^{n-2} x , dx \quad (n \ge 2)$&lt;/li&gt;
&lt;li&gt;$\int \ln^n x , dx = x \ln^n x - n \int \ln^{n-1} x , dx$&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h2&gt;5、 特殊定积分、广义积分与特殊函数（重点）&lt;/h2&gt;
&lt;h3&gt;(1). &lt;strong&gt;定积分对称性与变式&lt;/strong&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;偶奇性&lt;/strong&gt;：$\int_{-a}^a f(x) , dx = 0 \quad (f \text{ 为奇函数})$；$\int_{-a}^a f(x) , dx = 2\int_0^a f(x) , dx \quad (f \text{ 为偶函数})$&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;区间再现公式&lt;/strong&gt;：$\int_a^b f(x) , dx = \int_a^b f(a + b - x) , dx$&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;周期性&lt;/strong&gt;：若 $f(x)$ 周期为 $T$，则对任意 $a$，有 $\int_a^{a+T} f(x) , dx = \int_0^T f(x) , dx$&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;对称轴变化&lt;/strong&gt;：$\int_0^\pi x f(\sin x) , dx = \frac{\pi}{2} \int_0^\pi f(\sin x) , dx$&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;(2). &lt;strong&gt;经典广义积分（反常积分）&lt;/strong&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;高斯积分 (Gaussian Integral)&lt;/strong&gt;：&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;$$\int_{-\infty}^{+\infty} e^{-x^2} , dx = \sqrt{\pi}, \quad \int_0^{+\infty} e^{-x^2} , dx = \frac{\sqrt{\pi}}{2}$$&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;狄利克雷积分 (Dirichlet Integral)&lt;/strong&gt;：&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;$$\int_0^{+\infty} \frac{\sin x}{x} , dx = \frac{\pi}{2}$$&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;欧拉-菲涅耳积分 (Fresnel Integrals)&lt;/strong&gt;：&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;$$\int_0^{+\infty} \sin(x^2) , dx = \int_0^{+\infty} \cos(x^2) , dx = \frac{\sqrt{2\pi}}{4}$$&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;对数三角积分&lt;/strong&gt;：&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;$$\int_0^{\frac{\pi}{2}} \ln(\sin x) , dx = \int_0^{\frac{\pi}{2}} \ln(\cos x) , dx = -\frac{\pi}{2} \ln 2$$&lt;/p&gt;
&lt;h3&gt;(3). &lt;strong&gt;伽马函数（Gamma Function）与贝塔函数（Beta Function）&lt;/strong&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;$\Gamma(s) = \int_0^{+\infty} x^{s-1} e^{-x} , dx \quad (s &amp;gt; 0)$&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;性质：$\Gamma(s+1) = s\Gamma(s)$，当 $n$ 为整数时 $\Gamma(n+1) = n!$；$\Gamma\left(\frac{1}{2}\right) = \sqrt{\pi}$&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;$B(p, q) = \int_0^1 x^{p-1}(1-x)^{q-1} , dx = 2 \int_0^{\frac{\pi}{2}} \sin^{2p-1} \theta \cos^{2q-1} \theta , d\theta \quad (p &amp;gt; 0, q &amp;gt; 0)$&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;与 $\Gamma$ 函数的关系：&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;$$B(p, q) = \frac{\Gamma(p)\Gamma(q)}{\Gamma(p+q)}$$&lt;/p&gt;
&lt;hr /&gt;
&lt;h1&gt;三、常用等价无穷小&lt;/h1&gt;
&lt;hr /&gt;
&lt;h2&gt;1、 一阶基本等价无穷小（基础必备）&lt;/h2&gt;
&lt;p&gt;当 $x \to 0$（或 $\alpha(x) \to 0$）时：&lt;/p&gt;
&lt;h3&gt;(1). &lt;strong&gt;三角与反三角函数&lt;/strong&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;$\sin x \sim x$&lt;/li&gt;
&lt;li&gt;$\tan x \sim x$&lt;/li&gt;
&lt;li&gt;$\arcsin x \sim x$&lt;/li&gt;
&lt;li&gt;$\arctan x \sim x$&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;(2). &lt;strong&gt;指数与对数函数&lt;/strong&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;$e^x - 1 \sim x$&lt;/li&gt;
&lt;li&gt;$a^x - 1 \sim x \ln a \quad (a &amp;gt; 0, a \neq 1)$&lt;/li&gt;
&lt;li&gt;$\ln(1 + x) \sim x$&lt;/li&gt;
&lt;li&gt;$\log_a(1 + x) \sim \frac{x}{\ln a} \quad (a &amp;gt; 0, a \neq 1)$&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;(3). &lt;strong&gt;幂函数广义式&lt;/strong&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;$(1 + x)^\alpha - 1 \sim \alpha x \quad (\alpha \neq 0)$&lt;/li&gt;
&lt;li&gt;特别地：&lt;/li&gt;
&lt;li&gt;$\sqrt{1 + x} - 1 \sim \frac{1}{2} x$&lt;/li&gt;
&lt;li&gt;$\frac{1}{\sqrt{1 + x}} - 1 \sim -\frac{1}{2} x$&lt;/li&gt;
&lt;li&gt;$\sqrt[n]{1 + x} - 1 \sim \frac{1}{n} x$&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;(4). &lt;strong&gt;双曲与反双曲函数&lt;/strong&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;$\sinh x \sim x$&lt;/li&gt;
&lt;li&gt;$\tanh x \sim x$&lt;/li&gt;
&lt;li&gt;$\text{arsinh}, x \sim x$&lt;/li&gt;
&lt;li&gt;$\text{artanh}, x \sim x$&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h2&gt;2、 二阶与三阶等价无穷小（相减/差值核心）&lt;/h2&gt;
&lt;p&gt;在相减项抵消（如 $\tan x - \sin x$）或分母出现高阶项时，必须使用二阶或三阶等价无穷小：&lt;/p&gt;
&lt;h3&gt;(1). &lt;strong&gt;二阶型（$x^2$ 阶）&lt;/strong&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;$1 - \cos x \sim \frac{1}{2} x^2$&lt;/li&gt;
&lt;li&gt;$1 - \cos^\alpha x \sim \frac{\alpha}{2} x^2$&lt;/li&gt;
&lt;li&gt;$\cosh x - 1 \sim \frac{1}{2} x^2$&lt;/li&gt;
&lt;li&gt;$e^x - 1 - x \sim \frac{1}{2} x^2$&lt;/li&gt;
&lt;li&gt;$x - \ln(1 + x) \sim \frac{1}{2} x^2$&lt;/li&gt;
&lt;li&gt;$(1 + x) \ln(1 + x) - x \sim \frac{1}{2} x^2$&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;(2). &lt;strong&gt;三阶型（$x^3$ 阶 —— 高频难点）&lt;/strong&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;$x - \sin x \sim \frac{1}{6} x^3$&lt;/li&gt;
&lt;li&gt;$\arcsin x - x \sim \frac{1}{6} x^3$&lt;/li&gt;
&lt;li&gt;$\tan x - x \sim \frac{1}{3} x^3$&lt;/li&gt;
&lt;li&gt;$x - \arctan x \sim \frac{1}{3} x^3$&lt;/li&gt;
&lt;li&gt;$\tan x - \sin x \sim \frac{1}{2} x^3$&lt;/li&gt;
&lt;li&gt;$\arcsin x - \arctan x \sim \frac{1}{2} x^3$&lt;/li&gt;
&lt;li&gt;$\text{artanh}, x - x \sim \frac{1}{3} x^3$&lt;/li&gt;
&lt;li&gt;$x - \sinh x \sim -\frac{1}{6} x^3$&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h2&gt;3、 常用变体与复合结构（大题技巧）&lt;/h2&gt;
&lt;h3&gt;(1). &lt;strong&gt;指数与对数变形&lt;/strong&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;$e^{f(x)} - e^{g(x)} \sim e^{g(x)} (f(x) - g(x)) \quad (f(x), g(x) \to 0)$&lt;/li&gt;
&lt;li&gt;$\ln f(x) - \ln g(x) = \ln \left( 1 + \frac{f(x)-g(x)}{g(x)} \right) \sim \frac{f(x) - g(x)}{g(x)} \quad (f(x), g(x) \to 1)$&lt;/li&gt;
&lt;li&gt;$a^{f(x)} - b^{g(x)} \sim a^{f(x)} - b^{f(x)} + b^{f(x)} - b^{g(x)}$（常用于拆项）&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;(2). &lt;strong&gt;幂指函数型（$1^\infty$ 型求极限常用）&lt;/strong&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;$[1 + g(x)]^{f(x)} - 1 \sim f(x)g(x) \quad (g(x) \to 0, , f(x)g(x) \to 0)$&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h2&gt;4、 泰勒公式展开式（等价无穷小的根源）&lt;/h2&gt;
&lt;p&gt;当加减运算中低阶项被完全抵消时，&lt;strong&gt;等价无穷小代换失效&lt;/strong&gt;，必须直接使用泰勒展开（展开到首个非零系数项）：&lt;/p&gt;
&lt;p&gt;$$\begin{aligned} \sin x &amp;amp;= x - \frac{x^3}{6} + O(x^5) \ \cos x &amp;amp;= 1 - \frac{x^2}{2} + \frac{x^4}{24} + O(x^6) \ \tan x &amp;amp;= x + \frac{x^3}{3} + \frac{2x^5}{15} + O(x^5) \ \arcsin x &amp;amp;= x + \frac{x^3}{6} + \frac{3x^5}{40} + O(x^5) \ \arctan x &amp;amp;= x - \frac{x^3}{3} + \frac{x^5}{5} + O(x^5) \ e^x &amp;amp;= 1 + x + \frac{x^2}{2} + \frac{x^3}{6} + O(x^4) \ \ln(1 + x) &amp;amp;= x - \frac{x^2}{2} + \frac{x^3}{3} - \frac{x^4}{4} + O(x^4) \ (1 + x)^\alpha &amp;amp;= 1 + \alpha x + \frac{\alpha(\alpha - 1)}{2} x^2 + \frac{\alpha(\alpha - 1)(\alpha - 2)}{6} x^3 + O(x^3) \end{aligned}$$&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;5、 代换原则与避坑指南&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;核心原则：&lt;/strong&gt; 乘除直接换，加减慎重换。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;(1). &lt;strong&gt;乘除关系：&lt;/strong&gt; 若 $\alpha \sim \alpha&apos;$, $\beta \sim \beta&apos;$，则 $\lim \frac{\alpha \cdot \beta}{\dots} = \lim \frac{\alpha&apos; \cdot \beta&apos;}{\dots}$，可以无条件替换。&lt;/h3&gt;
&lt;h3&gt;(2). &lt;strong&gt;加减关系（代换条件）：&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;若要对 $\alpha - \beta$ 中的 $\alpha, \beta$ 分别替换为 $\alpha&apos;, \beta&apos;$：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;允许替换：&lt;/strong&gt; 当且仅当 $\lim \frac{\alpha&apos;}{\beta&apos;} \neq 1$（即两者不是同阶且同系数的无穷小）。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;禁止替换：&lt;/strong&gt; 若 $\lim \frac{\alpha&apos;}{\beta&apos;} = 1$（例如 $\tan x - \sin x$，若一阶替换变成 $x - x = 0$），直接替换会导致错解！此时必须使用&lt;strong&gt;高阶等价无穷小&lt;/strong&gt;（$\tan x - \sin x \sim \frac{1}{2}x^3$）或&lt;strong&gt;泰勒展开式&lt;/strong&gt;展开至相减后的首个非零项。&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h1&gt;四、常用的泰勒（Taylor）/ 麦克劳林（Maclaurin）公式&lt;/h1&gt;
&lt;h2&gt;1、 核心基本初等函数（熟记通项）&lt;/h2&gt;
&lt;h3&gt;(1). 指数与对数函数&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;指数函数 $e^x$&lt;/strong&gt;（收敛域：$(-\infty, +\infty)$）&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;$$e^x = 1 + x + \frac{x^2}{2!} + \frac{x^3}{3!} + \cdots + \frac{x^n}{n!} + o(x^n) = \sum_{k=0}^{n} \frac{x^k}{k!} + o(x^n)$$&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;特例变体：$a^x = e^{x \ln a} = \sum_{k=0}^n \frac{(\ln a)^k}{k!} x^k + o(x^n)$&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;对数函数 $\ln(1+x)$&lt;/strong&gt;（收敛域：$(-1, 1]$）&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;$$\ln(1+x) = x - \frac{x^2}{2} + \frac{x^3}{3} - \frac{x^4}{4} + \cdots + \frac{(-1)^{n-1}}{n}x^n + o(x^n) = \sum_{k=1}^n \frac{(-1)^{k-1}}{k} x^k + o(x^n)$$&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;对数函数 $\ln(1-x)$&lt;/strong&gt;（收敛域：$[-1, 1)$）&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;$$\ln(1-x) = -x - \frac{x^2}{2} - \frac{x^3}{3} - \cdots - \frac{x^n}{n} + o(x^n) = -\sum_{k=1}^n \frac{x^k}{k} + o(x^n)$$&lt;/p&gt;
&lt;hr /&gt;
&lt;h3&gt;(2). 三角函数与反三角函数&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;正弦函数 $\sin x$&lt;/strong&gt;（奇函数，收敛域：$(-\infty, +\infty)$）&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;$$\sin x = x - \frac{x^3}{3!} + \frac{x^5}{5!} - \frac{x^7}{7!} + \cdots + \frac{(-1)^n}{(2n+1)!} x^{2n+1} + o(x^{2n+2})$$&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;余弦函数 $\cos x$&lt;/strong&gt;（偶函数，收敛域：$(-\infty, +\infty)$）&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;$$\cos x = 1 - \frac{x^2}{2!} + \frac{x^4}{4!} - \frac{x^6}{6!} + \cdots + \frac{(-1)^n}{(2n)!} x^{2n} + o(x^{2n+1})$$&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;正切函数 $\tan x$&lt;/strong&gt;（奇函数，展开到 $x^5$ 或 $x^7$ 即可）&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;$$\tan x = x + \frac{1}{3}x^3 + \frac{2}{15}x^5 + \frac{17}{315}x^7 + o(x^7)$$&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;反正弦函数 $\arcsin x$&lt;/strong&gt;（奇函数，收敛域：$[-1, 1]$）&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;$$\arcsin x = x + \frac{1}{6}x^3 + \frac{3}{40}x^5 + \frac{5}{112}x^7 + \cdots + \frac{(2n)!}{4^n (n!)^2 (2n+1)} x^{2n+1} + o(x^{2n+2})$$&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;反切函数 $\arctan x$&lt;/strong&gt;（奇函数，收敛域：$[-1, 1]$）&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;$$\arctan x = x - \frac{x^3}{3} + \frac{x^5}{5} - \frac{x^7}{7} + \cdots + \frac{(-1)^n}{2n+1} x^{2n+1} + o(x^{2n+2})$$&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;正割函数 $\sec x$&lt;/strong&gt;（偶函数，高频）&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;$$\sec x = 1 + \frac{1}{2}x^2 + \frac{5}{24}x^4 + \frac{61}{720}x^6 + o(x^6)$$&lt;/p&gt;
&lt;hr /&gt;
&lt;h3&gt;(3). 二项式展开（Generalized Binomial Series）&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;一般幂函数 $(1+x)^\alpha$&lt;/strong&gt;（收敛域视 $\alpha$ 而定，至少在 $(-1, 1)$ 内收敛）&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;$$(1+x)^\alpha = 1 + \alpha x + \frac{\alpha(\alpha-1)}{2!} x^2 + \cdots + \frac{\alpha(\alpha-1)\cdots(\alpha-n+1)}{n!} x^n + o(x^n)$$&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;常见重要特例&lt;/strong&gt;：&lt;/li&gt;
&lt;li&gt;$\frac{1}{1-x} = 1 + x + x^2 + x^3 + \cdots + x^n + o(x^n) = \sum_{k=0}^n x^k + o(x^n) \quad (\vert{}x\vert{} &amp;lt; 1)$&lt;/li&gt;
&lt;li&gt;$\frac{1}{1+x} = 1 - x + x^2 - x^3 + \cdots + (-1)^n x^n + o(x^n) \quad (\vert{}x\vert{} &amp;lt; 1)$&lt;/li&gt;
&lt;li&gt;$\frac{1}{1+x^2} = 1 - x^2 + x^4 - x^6 + \cdots + (-1)^n x^{2n} + o(x^{2n+1})$&lt;/li&gt;
&lt;li&gt;$\sqrt{1+x} = 1 + \frac{1}{2}x - \frac{1}{8}x^2 + \frac{1}{16}x^3 - \frac{5}{128}x^4 + o(x^4)$&lt;/li&gt;
&lt;li&gt;$\frac{1}{\sqrt{1+x}} = 1 - \frac{1}{2}x + \frac{3}{8}x^2 - \frac{5}{16}x^3 + \frac{35}{128}x^4 + o(x^4)$&lt;/li&gt;
&lt;li&gt;$\frac{1}{\sqrt{1-x^2}} = 1 + \frac{1}{2}x^2 + \frac{3}{8}x^4 + \frac{5}{16}x^6 + o(x^6)$&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h2&gt;2、 双曲函数与反双曲函数&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;双曲正弦 $\sinh x$&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;$$\sinh x = \frac{e^x - e^{-x}}{2} = x + \frac{x^3}{3!} + \frac{x^5}{5!} + \cdots + \frac{x^{2n+1}}{(2n+1)!} + o(x^{2n+2})$$&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;双曲余弦 $\cosh x$&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;$$\cosh x = \frac{e^x + e^{-x}}{2} = 1 + \frac{x^2}{2!} + \frac{x^4}{4!} + \cdots + \frac{x^{2n}}{(2n)!} + o(x^{2n+1})$$&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;双曲正切 $\tanh x$&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;$$\tanh x = x - \frac{1}{3}x^3 + \frac{2}{15}x^5 - \frac{17}{315}x^7 + o(x^7)$$&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;反双曲正弦 $\text{arsinh } x = \ln(x + \sqrt{1+x^2})$&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;$$\text{arsinh } x = x - \frac{1}{6}x^3 + \frac{3}{40}x^5 - \frac{5}{112}x^7 + o(x^7)$$&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;反双曲正切 $\text{artanh } x = \frac{1}{2}\ln \frac{1+x}{1-x}$&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;$$\text{artanh } x = x + \frac{x^3}{3} + \frac{x^5}{5} + \frac{x^7}{7} + \cdots + \frac{x^{2n+1}}{2n+1} + o(x^{2n+2})$$&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;3、 高频复合结构与拆分展开&lt;/h2&gt;
&lt;p&gt;在计算中，常需要利用已知的基本展开式进行逐项相乘、复合或求导/积分：&lt;/p&gt;
&lt;h3&gt;(1). &lt;strong&gt;对数与余弦复合 $\ln(\cos x)$&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;$$\ln(\cos x) = \ln\left(1 - \frac{x^2}{2} + \frac{x^4}{24} + o(x^4)\right) = -\frac{1}{2}x^2 - \frac{1}{12}x^4 - \frac{1}{45}x^6 + o(x^6)$$&lt;/p&gt;
&lt;h3&gt;(2). &lt;strong&gt;指数与三角复合 $e^{\sin x}$ 与 $e^{\cos x}$&lt;/strong&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;$e^{\sin x} = 1 + x + \frac{1}{2}x^2 - \frac{1}{8}x^4 - \frac{1}{15}x^5 + o(x^5)$&lt;/li&gt;
&lt;li&gt;$e^{\cos x} = e \cdot e^{\cos x - 1} = e \left( 1 - \frac{x^2}{2} + \frac{x^4}{6} + o(x^4) \right)$&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;(3). &lt;strong&gt;正弦与正切复合 $\tan(\sin x)$ 与 $\sin(\tan x)$&lt;/strong&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;$\tan(\sin x) = x + \frac{1}{3}x^3 - \frac{1}{30}x^5 + o(x^5)$&lt;/li&gt;
&lt;li&gt;$\sin(\tan x) = x + \frac{1}{3}x^3 + \frac{1}{30}x^5 + o(x^5)$&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;经典差值&lt;/strong&gt;：$\tan(\sin x) - \sin(\tan x) \sim -\frac{1}{15} x^5$&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h2&gt;4、 泰勒余项的三种常见形式&lt;/h2&gt;
&lt;p&gt;在证明题或误差估计题中，余项形式的选择至关重要：&lt;/p&gt;
&lt;h3&gt;(1). &lt;strong&gt;皮亚诺（Peano）余项&lt;/strong&gt;（用于极限计算）&lt;/h3&gt;
&lt;p&gt;$$R_n(x) = o((x - x_0)^n)$$&lt;/p&gt;
&lt;h3&gt;(2). &lt;strong&gt;拉格朗日（Lagrange）余项&lt;/strong&gt;（用于中值定理证明与不等式证明）&lt;/h3&gt;
&lt;p&gt;$$R_n(x) = \frac{f^{(n+1)}(\xi)}{(n+1)!} (x - x_0)^{n+1} \quad (\xi \text{ 介于 } x_0 \text{ 与 } x \text{ 之间})$$&lt;/p&gt;
&lt;h3&gt;(3). &lt;strong&gt;积分余项&lt;/strong&gt;（用于推导估计与收敛性分析）&lt;/h3&gt;
&lt;p&gt;$$R_n(x) = \frac{1}{n!} \int_{x_0}^x (x - t)^n f^{(n+1)}(t) , dt$$&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;5、 泰勒展开在极限计算中的“确定展开阶数”原则&lt;/h2&gt;
&lt;h3&gt;(1). &lt;strong&gt;分式型极限&lt;/strong&gt;：&lt;/h3&gt;
&lt;p&gt;若分母是 $x^k$ 阶无穷小，分子必须展开到 $x^k$ 项（确保首个非零项显现）。&lt;/p&gt;
&lt;h3&gt;(2). &lt;strong&gt;作差型极限 $A - B$&lt;/strong&gt;：&lt;/h3&gt;
&lt;p&gt;将 $A$ 与 $B$ 分别展开，直到两者&lt;strong&gt;系数首次不相等&lt;/strong&gt;的那一项为止，前面抵消的低阶项即为消去项。&lt;/p&gt;
</content:encoded></item><item><title>OpenList 升级到 4.2.2 后 Waline 评论失效？根本原因和完整修复方案</title><link>https://006lp.de/posts/openlist-waline-comment-fix/</link><guid isPermaLink="true">https://006lp.de/posts/openlist-waline-comment-fix/</guid><description>OpenList 升级到 4.2.2 后，写在 README 元数据里的 Waline 评论脚本突然失效——CSS 加载正常，JS 却毫无动静，评论区高度为 0。本文从 PR #2346 的 commit diff 出发，详细分析根本原因（FilterReadMeScripts 从后端迁移到前端导致 script type=module 被过滤），并给出完整可用的修复方案。</description><pubDate>Mon, 08 Jun 2026 13:30:00 GMT</pubDate><content:encoded>&lt;p&gt;升级完 OpenList 的那一刻，我以为只是常规的 bugfix 更新，结果打开主页一看——评论区消失了。&lt;/p&gt;
&lt;p&gt;CSS 好端端的，Waline 的样式文件请求返回 200，但 &lt;code&gt;&amp;lt;div id=&quot;waline&quot;&amp;gt;&lt;/code&gt; 里空空如也，高度是一个令人绝望的 &lt;code&gt;908.812×0&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;折腾了一段时间之后，把问题锁定在了 v4.2.2 的一个 Breaking Change 上。这篇文章就把整个来龙去脉记录下来，顺带把修复方案整合一下，希望踩过同样坑的朋友少花点时间。&lt;/p&gt;
&lt;h2&gt;问题复现&lt;/h2&gt;
&lt;p&gt;根据 &lt;a href=&quot;https://waline.js.org/guide/get-started/#html-%E5%BC%95%E5%85%A5&quot;&gt;Waline快速上手中的方案&lt;/a&gt;，在旧版本（≤ 4.1.10）中仅需在主页的&lt;strong&gt;元数据 README&lt;/strong&gt; 里写一段 HTML，CSS 和 JS 全部内联：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;!-- Waline 容器 --&amp;gt;
&amp;lt;link rel=&quot;stylesheet&quot; href=&quot;https://unpkg.com/@waline/client@v3/dist/waline.css&quot; /&amp;gt;
&amp;lt;div id=&quot;waline-comment&quot; style=&quot;margin: 20px auto; max-width: 960px;&quot;&amp;gt;
  &amp;lt;h2 style=&quot;text-align:center&quot;&amp;gt;- 评论 Comments -&amp;lt;/h2&amp;gt;
  &amp;lt;div id=&quot;waline&quot;&amp;gt;&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;

&amp;lt;!-- Waline JS 初始化 --&amp;gt;
&amp;lt;script type=&quot;module&quot;&amp;gt;
  import { init } from &apos;https://unpkg.com/@waline/client@v3/dist/waline.js&apos;;
  init({
    el: &apos;#waline&apos;,
    serverURL: &apos;https://comments.example.com&apos;,
    emoji: false,
    comment: true,
    search: false,
    path: window.location.pathname,
  });
&amp;lt;/script&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;升级到 4.2.2 之后，这段代码的表现变成：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;&amp;lt;link&amp;gt;&lt;/code&gt; 的 CSS 请求正常发出并返回 ✅&lt;/li&gt;
&lt;li&gt;&lt;code&gt;&amp;lt;script type=&quot;module&quot;&amp;gt;&lt;/code&gt; 中的 JS &lt;strong&gt;完全没有执行&lt;/strong&gt; ❌&lt;/li&gt;
&lt;li&gt;&lt;code&gt;#waline&lt;/code&gt; 容器尺寸为 &lt;code&gt;908.812×0&lt;/code&gt;（宽度撑开了，但高度为 0，Waline 从未初始化）❌&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;根本原因：PR #2346 把过滤逻辑从后端搬到了前端&lt;/h2&gt;
&lt;p&gt;v4.2.2 的 Release Notes 里有两条 Breaking Changes，其中一条就是：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;settings&lt;/strong&gt;: Move FilterReadMeScripts to frontend - by @xrgzs in #2346&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;这条改动对应 commit &lt;code&gt;a5ba6a0&lt;/code&gt;，看一下实际 diff 就很清楚了。&lt;/p&gt;
&lt;h3&gt;旧版后端做了什么&lt;/h3&gt;
&lt;p&gt;旧版的 &lt;code&gt;server/handles/down.go&lt;/code&gt; 在代理 &lt;code&gt;.md&lt;/code&gt; 文件时，如果 &lt;code&gt;FilterReadMeScripts&lt;/code&gt; 开关为 &lt;code&gt;true&lt;/code&gt;（默认开启），会在&lt;strong&gt;后端&lt;/strong&gt;走一套完整的处理流水线：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;用 &lt;code&gt;goldmark&lt;/code&gt; 把 Markdown 源文件渲染成 HTML&lt;/li&gt;
&lt;li&gt;用 &lt;code&gt;bluemonday&lt;/code&gt; 的 UGC Policy 对 HTML 进行 sanitize（消毒）&lt;/li&gt;
&lt;li&gt;把清洗过的 HTML 以 &lt;code&gt;text/html&lt;/code&gt; 形式返回给前端&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;code&gt;bluemonday&lt;/code&gt; 的 UGC Policy 会&lt;strong&gt;剥除 &lt;code&gt;&amp;lt;script&amp;gt;&lt;/code&gt;、&lt;code&gt;&amp;lt;link&amp;gt;&lt;/code&gt; 等危险标签&lt;/strong&gt;，这是它的设计初衷。但这套流水线只在&lt;strong&gt;直接代理 &lt;code&gt;.md&lt;/code&gt; 文件&lt;/strong&gt;时（走 &lt;code&gt;/d/&lt;/code&gt; 路径）才触发，主页展示 README 走的是 &lt;code&gt;/api/fs/get&lt;/code&gt; API 接口，后端直接原样返回 Markdown 内容，不经过 bluemonday。&lt;/p&gt;
&lt;p&gt;所以旧版真正起作用的机制在前端：前端把 README 内容渲染为 HTML 注入到页面后，会对其中的 &lt;code&gt;&amp;lt;script&amp;gt;&lt;/code&gt; 标签做一次&lt;strong&gt;克隆重新 append&lt;/strong&gt; 的处理，让它们实际执行。&lt;code&gt;&amp;lt;script type=&quot;module&quot;&amp;gt;&lt;/code&gt; 就是通过这个机制被触发的。&lt;/p&gt;
&lt;h3&gt;新版改动：32 行代码的删除&lt;/h3&gt;
&lt;p&gt;commit &lt;code&gt;a5ba6a0&lt;/code&gt; 从 &lt;code&gt;down.go&lt;/code&gt; 里&lt;strong&gt;整体删除&lt;/strong&gt;了那 31 行后端清洗逻辑，同时移除了对 &lt;code&gt;goldmark&lt;/code&gt; 和 &lt;code&gt;bluemonday&lt;/code&gt; 两个依赖库的引用，并在 &lt;code&gt;setting.go&lt;/code&gt; 里给 &lt;code&gt;FilterReadMeScripts&lt;/code&gt; 的配置加上了注释 &lt;code&gt;// frontend&lt;/code&gt;，意思是：这个开关的实际执行逻辑已经全部交给前端负责了。&lt;/p&gt;
&lt;p&gt;这是一次架构上的合理重构——把视图层的过滤放在前端做，后端减负，逻辑更清晰。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;但问题在于&lt;/strong&gt;：前端新版本对 README 内容里 &lt;code&gt;&amp;lt;script&amp;gt;&lt;/code&gt; 标签的处理比之前更严格，&lt;code&gt;type=&quot;module&quot;&lt;/code&gt; 形式的脚本会被&lt;strong&gt;直接过滤掉，不再执行&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;这就解释了所有现象：&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;现象&lt;/th&gt;
&lt;th&gt;原因&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;CSS 正常加载&lt;/td&gt;
&lt;td&gt;&lt;code&gt;&amp;lt;link&amp;gt;&lt;/code&gt; 标签通过了前端的过滤，或走了不同处理路径&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;JS 完全不执行&lt;/td&gt;
&lt;td&gt;&lt;code&gt;&amp;lt;script type=&quot;module&quot;&amp;gt;&lt;/code&gt; 被前端新过滤器丢弃&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;#waline&lt;/code&gt; 高度为 0&lt;/td&gt;
&lt;td&gt;容器 div 存在，但 Waline 从未初始化，内容为空&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;顺便一提，&lt;code&gt;&amp;lt;script type=&quot;module&quot;&amp;gt;&lt;/code&gt; 在被 &lt;code&gt;innerHTML&lt;/code&gt; 动态插入 DOM 时，浏览器本身也不会自动执行——这是浏览器的安全规范，ES Module 的 &lt;code&gt;import&lt;/code&gt; 语义只在顶层脚本上下文有效。所以即使前端没过滤，不经过特殊处理的 module script 也跑不起来。旧版前端的克隆 append 机制恰好绕过了这个限制，新版则没有。&lt;/p&gt;
&lt;h2&gt;完整修复方案&lt;/h2&gt;
&lt;p&gt;修复思路是把代码分散到三个不同的注入点，各司其职，完全绕开 README 的过滤器：&lt;/p&gt;
&lt;h3&gt;第一步：自定义头部（Custom Head）—— 放 CSS&lt;/h3&gt;
&lt;p&gt;进入 &lt;strong&gt;设置 → 全局 → 自定义头部&lt;/strong&gt;，填入：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;link rel=&quot;stylesheet&quot; href=&quot;https://unpkg.com/@waline/client@v3/dist/waline.css&quot;&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;&amp;lt;head&amp;gt;&lt;/code&gt; 里的 &lt;code&gt;&amp;lt;link&amp;gt;&lt;/code&gt; 走标准 HTML 解析路径，完全不经过任何 README 过滤器，稳定可靠。&lt;/p&gt;
&lt;h3&gt;第二步：自定义 Body（Custom Body）—— 放 JS 初始化逻辑&lt;/h3&gt;
&lt;p&gt;进入 &lt;strong&gt;设置 → 全局 → 自定义 Body&lt;/strong&gt;，填入以下完整代码：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;!-- 引入 UMD 版本的 Waline（挂载到 window.Waline 全局变量） --&amp;gt;
&amp;lt;script src=&quot;https://unpkg.com/@waline/client@v3/dist/waline.umd.js&quot;&amp;gt;&amp;lt;/script&amp;gt;
&amp;lt;script&amp;gt;
(function() {
  let walineInstance = null;
  let initTimer = null;

  function doInitWaline() {
    const walineEl = document.querySelector(&apos;#waline&apos;);
    if (!walineEl || typeof Waline === &apos;undefined&apos;) return;
    // 容器内已有内容，说明 Waline 正常挂载着，无需重复初始化
    if (walineEl.children.length &amp;gt; 0) return;
    // 有旧实例先销毁，防止内存泄漏
    if (walineInstance &amp;amp;&amp;amp; typeof walineInstance.destroy === &apos;function&apos;) {
      try { walineInstance.destroy(); } catch(e) {}
      walineInstance = null;
    }
    walineInstance = Waline.init({
      el: &apos;#waline&apos;,
      serverURL: &apos;https://comments.example.xyz&apos;, // 替换为你的 Waline 服务地址
      emoji: false,
      comment: true,
      search: false,
      path: window.location.pathname,
    });
  }

  // 防抖：SPA 路由切换时 DOM 频繁变动，延迟 300ms 等待稳定
  function debouncedInit() {
    clearTimeout(initTimer);
    initTimer = setTimeout(doInitWaline, 300);
  }

  // 1. 页面首次加载
  doInitWaline();

  // 2. 监听 DOM 变化（SPA 框架动态重建 DOM 时触发）
  const observer = new MutationObserver(debouncedInit);
  observer.observe(document.body, { childList: true, subtree: true });

  // 3. 拦截 History API（前进/后退/框架内部路由跳转）
  const originalPushState = history.pushState;
  const originalReplaceState = history.replaceState;
  history.pushState = function() {
    originalPushState.apply(this, arguments);
    debouncedInit();
  };
  history.replaceState = function() {
    originalReplaceState.apply(this, arguments);
    debouncedInit();
  };
  window.addEventListener(&apos;popstate&apos;, debouncedInit);
})();
&amp;lt;/script&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;为什么改用 UMD 而不是 ESM？&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;原来的 &lt;code&gt;import { init } from &apos;...waline.js&apos;&lt;/code&gt; 是 ES Module 写法，有两个问题：一是动态插入的 &lt;code&gt;&amp;lt;script type=&quot;module&quot;&amp;gt;&lt;/code&gt; 浏览器不执行；二是前端过滤器会丢弃它。改用 &lt;code&gt;waline.umd.js&lt;/code&gt; 后，脚本加载后直接把 &lt;code&gt;Waline&lt;/code&gt; 挂到 &lt;code&gt;window&lt;/code&gt; 上，后续代码用 &lt;code&gt;Waline.init()&lt;/code&gt; 调用，完全是普通的全局变量方式，没有任何模块化限制。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;为什么需要 MutationObserver 和 History API 拦截？&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;OpenList 是基于 SolidJS 的 SPA（单页应用）。当你从别的目录切换回主页时，整个 DOM 树会被 SolidJS 销毁并重建，之前初始化的 Waline 实例也随之消失。如果只在页面加载时初始化一次，路由切换回来后评论区就空了。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;MutationObserver&lt;/code&gt; 监听 &lt;code&gt;document.body&lt;/code&gt; 的子树变化，每次 DOM 重建后都会触发重新初始化；&lt;code&gt;history.pushState/replaceState&lt;/code&gt; 的拦截则覆盖了框架内部路由跳转的场景；300ms 防抖避免 DOM 频繁变动时重复触发。&lt;/p&gt;
&lt;h3&gt;第三步：主页元数据 README —— 只保留容器 div&lt;/h3&gt;
&lt;p&gt;回到主页元数据，把 &lt;code&gt;&amp;lt;script&amp;gt;&lt;/code&gt; 和 &lt;code&gt;&amp;lt;link&amp;gt;&lt;/code&gt; 全部删掉，只保留 HTML 容器：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;div id=&quot;waline-comment&quot; style=&quot;margin: 20px auto; max-width: 960px;&quot;&amp;gt;
  &amp;lt;h2 style=&quot;text-align:center&quot;&amp;gt;- 评论 Comments -&amp;lt;/h2&amp;gt;
  &amp;lt;div id=&quot;waline&quot;&amp;gt;&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;纯粹的 &lt;code&gt;&amp;lt;div&amp;gt;&lt;/code&gt; 不含任何可执行内容，不会被任何过滤器动到。JS 找到这个 &lt;code&gt;#waline&lt;/code&gt; 容器后负责挂载，CSS 从 &lt;code&gt;&amp;lt;head&amp;gt;&lt;/code&gt; 里来，三方各归其位。&lt;/p&gt;
&lt;h2&gt;三种注入点的本质区别&lt;/h2&gt;
&lt;p&gt;理解这三个位置的差异，以后遇到类似问题就不会懵了：&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;注入点&lt;/th&gt;
&lt;th&gt;处理机制&lt;/th&gt;
&lt;th&gt;能跑 &lt;code&gt;&amp;lt;script&amp;gt;&lt;/code&gt;？&lt;/th&gt;
&lt;th&gt;能跑 &lt;code&gt;&amp;lt;link&amp;gt;&lt;/code&gt;？&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;主页元数据 README&lt;/td&gt;
&lt;td&gt;前端 Markdown 渲染 + 新版过滤器&lt;/td&gt;
&lt;td&gt;❌（被过滤）&lt;/td&gt;
&lt;td&gt;看情况，不稳定&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;自定义 Body&lt;/td&gt;
&lt;td&gt;直接注入 &lt;code&gt;&amp;lt;body&amp;gt;&lt;/code&gt;，不走 README 过滤器&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;自定义 Head&lt;/td&gt;
&lt;td&gt;注入 &lt;code&gt;&amp;lt;head&amp;gt;&lt;/code&gt;，标准 HTML 解析&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;README 的设计初衷是内容展示，过滤脚本是合理的安全考量。需要执行 JS 的逻辑就应该放到 Custom Body/Head 这两个专门为此设计的位置。&lt;/p&gt;
</content:encoded></item><item><title>逆向解析 ColorOS 离线号码库 (三)：携号转网的二分查找与高并发全量导出</title><link>https://006lp.de/posts/reverse-coloros-offline-number-lookup/binary-search-mnp-export-coloros-3/</link><guid isPermaLink="true">https://006lp.de/posts/reverse-coloros-offline-number-lookup/binary-search-mnp-export-coloros-3/</guid><description>作为系列终章，本节攻克携号转网（MNP）特权数据库 `PortabilityNumberData.dat`：揭秘 11 字节极致存储模型（8 字节号码 + 2 字节城市 + 1 字节运营商），还原基于文件指针的二分查找算法，实现百万级转网号码的毫秒级精准查询。最终整合前两节成果，利用 Python 多进程并发技术，编写工业级全量导出脚本，1~2 秒内完成 70 万号段的归属地 + 运营商全息数据提取。</description><pubDate>Sat, 14 Mar 2026 14:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;逆向解析 ColorOS 离线号码库 (三)：携号转网的二分查找与高并发全量导出&lt;/h1&gt;
&lt;h2&gt;0. 前言&lt;/h2&gt;
&lt;p&gt;在前两节中，我们成功剥离了 ColorOS 底层的 12-Bit 归属地压缩算法与多级指针寻址的运营商识别模型，并修复了历史遗留的区号重定向问题。&lt;/p&gt;
&lt;p&gt;然而，基于“前 7 位号段”的查询逻辑存在一个无法逾越的物理死角——&lt;strong&gt;携号转网（MNP）&lt;/strong&gt;。当一个原本属于“北京移动”的用户带着号码转入“中国电信”时，传统的号段映射将彻底失效。本节，我们将揭开最后一个特权数据库 &lt;code&gt;PortabilityNumberData.dat&lt;/code&gt; 的面纱，并利用 Python 的多进程并发技术，编写一个秒级导出百万号段的全量查询脚本。&lt;/p&gt;
&lt;h2&gt;1. 应对携号转网：特权白名单机制&lt;/h2&gt;
&lt;p&gt;由于携号转网的号码没有任何规律可言，无法像普通号码那样进行前缀压缩。OPPO 工程师在此引入了最高优先级的特权数据库：&lt;code&gt;PortabilityNumberData.dat&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;系统在处理任何来电时，其真实的宏观调度逻辑如下：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;查询转网特权库&lt;/strong&gt;：先在 &lt;code&gt;PortabilityNumberData.dat&lt;/code&gt; 中精确查找 11 位完整号码。若命中，直接提取新的归属地和运营商，查询终止。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;查询常规号段库&lt;/strong&gt;：若未命中，说明是未转网的常规号码。系统截取前 7 位，走我们前两节逆向出的普通库（&lt;code&gt;PhoneNumberData&lt;/code&gt; + &lt;code&gt;CarrierData&lt;/code&gt;）进行解析。&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;2. 解析 PortabilityNumberData 数据结构&lt;/h2&gt;
&lt;p&gt;既然没有任何规律，最简单粗暴的方法就是把 11 位完整的手机号存下来。但如果我们把数以百万计的转网号码全部塞进文件，每次来电都从头遍历，必然会导致严重的性能灾难。&lt;/p&gt;
&lt;p&gt;通过反编译 &lt;code&gt;PortabilityNumbersUtil.kt&lt;/code&gt;，我们看到了堪称教科书级别的空间优化与&lt;strong&gt;二分查找 (Binary Search)&lt;/strong&gt; 算法应用。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://files.seeusercontent.com/2026/03/14/2Ibv/image.jpg&quot; alt=&quot;image.jpg&quot; /&gt;&lt;/p&gt;
&lt;h3&gt;2.1 极致的 11 字节存储模型&lt;/h3&gt;
&lt;p&gt;在反编译的 &lt;code&gt;a(String str, long j3)&lt;/code&gt; 方法中，我们发现每条转网记录在底层仅占用 &lt;strong&gt;11 个字节&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;8 字节 (&lt;code&gt;long&lt;/code&gt;)&lt;/strong&gt;：存储 11 位完整的手机号码。由于 11 位数字（如 13812345678）超出了 32 位 &lt;code&gt;int&lt;/code&gt; 的最大值（21亿），必须采用 64 位长整型。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;2 字节 (&lt;code&gt;short&lt;/code&gt;)&lt;/strong&gt;：新的城市 ID。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;1 字节 (&lt;code&gt;byte&lt;/code&gt;)&lt;/strong&gt;：新的运营商 ID。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这意味着，即使全国有 100 万个携号转网用户，该文件的主体体积也仅有约 &lt;strong&gt;10.4 MB&lt;/strong&gt;。&lt;/p&gt;
&lt;h3&gt;2.2 毫秒级寻址的二分查找&lt;/h3&gt;
&lt;p&gt;为了在 100 万个记录中实现极速查询，整个二进制文件内部是&lt;strong&gt;严格按号码大小升序排列&lt;/strong&gt;的。代码中实现了一个底层的文件流二分查找：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;int left = 0; 
// right 是总记录数
while (left &amp;lt;= right) {
    int mid = (right + left) / 2; 
    
    // 核心：根据 mid 算出绝对字节偏移，直接移动文件指针
    randomAccessFile.seek((mid * 11) + baseOffset); 
    
    // 读取 8 字节的长整型号码
    long currentNumber = randomAccessFile.readLong(); 
    
    if (targetNumber &amp;gt; currentNumber) {
        left = mid + 1; // 去右半边找
    } else if (targetNumber == currentNumber) {
        // 命中！紧接着读取 2 字节城市 ID 和 1 字节运营商 ID
        return new Result(randomAccessFile.readShort(), randomAccessFile.readByte());
    } else {
        right = mid - 1; // 去左半边找
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;通过二分查找，在 100 万条数据中定位特定号码最多只需查找 $\log_2(1000000) \approx 20$ 次。磁盘指针仅需跳转 20 次，耗时在 1 毫秒以内，完美兼顾了存储空间与查询性能。&lt;/p&gt;
&lt;h2&gt;3. 终极实战：高并发全量导出脚本&lt;/h2&gt;
&lt;p&gt;作为本次逆向工程的最终目标，我们需要将 &lt;code&gt;1300000&lt;/code&gt; 到 &lt;code&gt;1999999&lt;/code&gt; 整整 70 万个基础号段（抛开携号转网的特例）的全息数据，极速导出为 &lt;code&gt;.csv&lt;/code&gt; 文件。&lt;/p&gt;
&lt;p&gt;为了满足 &lt;strong&gt;“高并发、极速、有序”&lt;/strong&gt; 的要求，我们利用 Python 的 &lt;code&gt;multiprocessing&lt;/code&gt; 多进程模块。核心优化点如下：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;消除 IPC 瓶颈&lt;/strong&gt;：利用进程池的 &lt;code&gt;initializer&lt;/code&gt; 参数，让每个 CPU 核心在启动时，独立将几个 MB 的数据库加载到自己的内存中，避免了昂贵的进程间数据传递。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;严格保序&lt;/strong&gt;：使用 &lt;code&gt;pool.map&lt;/code&gt; 替代普通异步回调，它会自动阻塞并按照任务分配的顺序重组结果列表，确保导出的 CSV 文件从 130 严格递增至 199。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;完整的导出脚本 (&lt;code&gt;export_all_phones.py&lt;/code&gt;)：&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;import os
import struct
import csv
import time
from multiprocessing import Pool, cpu_count

# ==========================================
# 全局变量，用于子进程共享内存数据
# ==========================================
loc_data = None
car_data = None

# ==========================================
# 模块 1：归属地数据库解析
# ==========================================
def load_location_db(file_path, patch_file):
    with open(file_path, &apos;rb&apos;) as f:
        data = f.read()

    tail_data = data[-12002:]
    area_codes_raw = tail_data[2:2002]
    city_names_raw = tail_data[2002:10002]
    extend_prefix_raw = tail_data[10002:12002]

    cities = []
    for i in range(400):
        area = area_codes_raw[i*5 : i*5+5].decode(&apos;ascii&apos;, errors=&apos;ignore&apos;).strip()
        name_bytes = city_names_raw[i*20 : i*20+20].split(b&apos;\x00&apos;)[0]
        name = name_bytes.decode(&apos;gbk&apos;, errors=&apos;ignore&apos;).strip()
        cities.append([area, name])

    # 加载官方补丁 治愈 9999
    if os.path.exists(patch_file):
        with open(patch_file, &quot;r&quot;, encoding=&quot;utf-8&quot;) as f:
            lines = f.readlines()
            for line in lines[1:]:
                parts = line.strip().split(&apos;\t&apos;)
                if len(parts) == 4:
                    origin_id = int(parts[0])
                    equal_id = int(parts[2])
                    if equal_id - 1 &amp;lt; len(cities) and origin_id - 1 &amp;lt; len(cities):
                        target_area, target_name = cities[equal_id - 1]
                        cities[origin_id - 1][0] = target_area
                        # cities[origin_id - 1][1] = target_name

    prefix_map = {}
    base_idx = 0
    for p in range(130, 140): prefix_map[str(p)] = base_idx; base_idx += 10000
    for p in range(150, 160): prefix_map[str(p)] = base_idx; base_idx += 10000
    prefix_map[&quot;188&quot;] = base_idx; base_idx += 10000
    prefix_map[&quot;189&quot;] = base_idx; base_idx += 10000

    for i in range(1000):
        b1 = extend_prefix_raw[i*2]
        b2 = extend_prefix_raw[i*2 + 1]
        prefix_val = (b1 &amp;lt;&amp;lt; 8) | b2
        if prefix_val == 0: break
        prefix_map[str(prefix_val)] = base_idx
        base_idx += 10000

    binary_array = data[16 : -12002]
    return prefix_map, cities, binary_array

# ==========================================
# 模块 2：运营商数据库解析
# ==========================================
def load_carrier_db(file_path):
    with open(file_path, &apos;rb&apos;) as f:
        data = f.read()

    offset = 16 
    carrier_names = {}
    num_carriers = struct.unpack_from(&quot;&amp;gt;H&quot;, data, offset)[0]
    offset += 2
    for _ in range(num_carriers):
        carrier_id = struct.unpack_from(&quot;&amp;gt;H&quot;, data, offset)[0]
        offset += 2
        names = []
        for _ in range(4):
            str_len = struct.unpack_from(&quot;&amp;gt;H&quot;, data, offset)[0]
            offset += 2
            if str_len &amp;gt; 0:
                name = data[offset : offset + str_len].decode(&apos;utf-8&apos;, errors=&apos;ignore&apos;)
                offset += str_len
            else:
                name = &quot;&quot;
            names.append(name)
        carrier_names[carrier_id] = names

    general_prefixes = {}
    num_gen_prefixes = struct.unpack_from(&quot;&amp;gt;H&quot;, data, offset)[0]
    offset += 2
    for _ in range(num_gen_prefixes):
        prefix_val = struct.unpack_from(&quot;&amp;gt;i&quot;, data, offset)[0]
        offset += 4
        cid = struct.unpack_from(&quot;&amp;gt;H&quot;, data, offset)[0]
        offset += 2
        general_prefixes[str(prefix_val)] = cid

    detailed_prefixes = {}
    num_det_prefixes = struct.unpack_from(&quot;&amp;gt;H&quot;, data, offset)[0]
    offset += 2
    for _ in range(num_det_prefixes):
        prefix_val = struct.unpack_from(&quot;&amp;gt;i&quot;, data, offset)[0]
        offset += 4
        file_offset = struct.unpack_from(&quot;&amp;gt;i&quot;, data, offset)[0]
        offset += 4
        detailed_prefixes[str(prefix_val)] = file_offset

    return data, carrier_names, general_prefixes, detailed_prefixes

# ==========================================
# 模块 3：子进程初始化与工作函数
# ==========================================
def init_worker(loc_file, car_file, patch_file):
    &quot;&quot;&quot;
    初始化每个 CPU 核心的工作进程，把数据库装载到子进程的内存中。
    这样不需要在进程间传递几兆的数据，极大提升性能。
    &quot;&quot;&quot;
    global loc_data, car_data
    loc_data = load_location_db(loc_file, patch_file)
    car_data = load_carrier_db(car_file)

def process_chunk(args):
    &quot;&quot;&quot;
    处理分配到的号码区间，例如 1300000 到 1309999
    &quot;&quot;&quot;
    start_num, end_num = args
    results = []
    prefix_map, cities, binary_array = loc_data
    car_raw_data, carrier_names, general_prefixes, detailed_prefixes = car_data

    for phone_int in range(start_num, end_num + 1):
        phone_7 = str(phone_int)
        
        # 运营商的底层查询需要 4 位后缀，为了凑齐 8 位进行偏移运算，安全补齐到 11 位
        eval_phone = phone_7 + &quot;0000&quot;  

        # --- A. 归属地极速查询 ---
        prefix = phone_7[:3]
        suffix = phone_7[3:]
        loc_name = &quot;&quot;
        
        if prefix in prefix_map:
            absolute_index = prefix_map[prefix] + int(suffix)
            byte_offset = (absolute_index // 2) * 3
            if byte_offset + 2 &amp;lt; len(binary_array):
                b1, b2, b3 = binary_array[byte_offset:byte_offset+3]
                city_id = (b1 &amp;lt;&amp;lt; 4) | (b2 &amp;gt;&amp;gt; 4) if absolute_index % 2 == 0 else ((b2 &amp;amp; 0x0F) &amp;lt;&amp;lt; 8) | b3
                if city_id != 0 and city_id &amp;lt; len(cities):
                    _, loc_name = cities[city_id]

        if not loc_name:
            loc_name = &quot;未知&quot;

        # --- B. 运营商极速查询 ---
        carrier_name = &quot;&quot;
        found_carrier = False

        # 1. 查精细号段偏移（如虚拟运营商）
        for length in range(4, 2, -1):
            p_prefix = eval_phone[:length]
            if p_prefix in detailed_prefixes:
                p_suffix = eval_phone[length : length+4]
                if len(p_suffix) == 4:
                    target_offset = detailed_prefixes[p_prefix] + (int(p_suffix) * 2)
                    if target_offset + 2 &amp;lt;= len(car_raw_data):
                        cid = struct.unpack_from(&quot;&amp;gt;H&quot;, car_raw_data, target_offset)[0]
                        if cid in carrier_names:
                            carrier_name = carrier_names[cid][0] or carrier_names[cid][1]
                            found_carrier = True
                            break

        # 2. 查全局号段 (如移动/联通基础号段)
        if not found_carrier:
            for length in range(4, 2, -1):
                p_prefix = eval_phone[:length]
                if p_prefix in general_prefixes:
                    cid = general_prefixes[p_prefix]
                    if cid in carrier_names:
                        carrier_name = carrier_names[cid][0] or carrier_names[cid][1]
                        break

        if not carrier_name:
            carrier_name = &quot;未知&quot;

        # 如果这个号段在两大数据库里全都是“未知”，说明这是一个彻头彻尾的空号段，直接跳过不写入
        if loc_name == &quot;未知&quot; and carrier_name == &quot;未知&quot;:
            continue

        results.append(f&quot;{phone_7},{loc_name},{carrier_name}\n&quot;)

    return results

# ==========================================
# 主程序：分发任务并整合写入
# ==========================================
def main():
    loc_file = &quot;E:/APKS/PhoneNumberData_3_1_0.dat&quot;
    car_file = &quot;E:/APKS/CarrierData_1_0.dat&quot;
    patch_file = &quot;E:/APKS/Multi_Areano_Table.txt&quot;
    out_file = &quot;phonenumber-fin.csv&quot;

    if not all(os.path.exists(f) for f in [loc_file, car_file, patch_file]):
        print(&quot;❌ 缺少必要的文件，请检查目录！&quot;)
        return

    start_num = 1300000
    end_num   = 1999999
    chunk_size = 20000  # 每个 CPU 分配两万个号码处理

    # 计算区块分配范围
    chunks = []
    for i in range(start_num, end_num + 1, chunk_size):
        chunk_end = min(i + chunk_size - 1, end_num)
        chunks.append((i, chunk_end))

    total_chunks = len(chunks)
    cores = cpu_count()
    print(&quot;=&quot; * 50)
    print(f&quot;🚀 准备火力全开进行高并发全息扫描...&quot;)
    print(f&quot;🎯 扫描区间: {start_num} - {end_num} (共 {end_num - start_num + 1} 个号段)&quot;)
    print(f&quot;⚙️  调用核心: {cores} 个 CPU 核心&quot;)
    print(&quot;=&quot; * 50)

    start_time = time.time()

    # 创建进程池，使用 map 确保按顺序返回
    with Pool(processes=cores, initializer=init_worker, initargs=(loc_file, car_file, patch_file)) as pool:
        # pool.map 会阻塞并收集全部结果，并且严格保证结果列表顺序等于 chunks 顺序
        all_results = pool.map(process_chunk, chunks)

    print(f&quot;✅ 扫描计算完毕，耗时: {time.time() - start_time:.2f} 秒。正在合并且保存...&quot;)

    # 将结果按照顺序写入 CSV 
    # CSV 只会保存真正有归属地或运营商记录的真实号段，抛弃了无用垃圾号段
    written_count = 0
    with open(out_file, &apos;w&apos;, encoding=&apos;utf-8-sig&apos;) as f:
        f.write(&quot;号段前缀,归属城市,网络运营商\n&quot;)  # 写入表头
        for chunk_result in all_results:
            if chunk_result:
                f.writelines(chunk_result)
                written_count += len(chunk_result)

    print(&quot;=&quot; * 50)
    print(f&quot;🎉 导出大功告成！&quot;)
    print(f&quot;📁 导出文件: {out_file}&quot;)
    print(f&quot;📊 有效号段: {written_count} 条记录&quot;)
    print(f&quot;⏱️  总计耗时: {time.time() - start_time:.2f} 秒&quot;)
    print(&quot;=&quot; * 50)

if __name__ == &apos;__main__&apos;:
    main()
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;利用多核 CPU 的并行计算，这 70 万个号段的数据提取在现代处理器上通常只需 &lt;strong&gt;1~2 秒&lt;/strong&gt;即可跑完，真正做到了工业级的性能表现。&lt;/p&gt;
&lt;h2&gt;4. 全系列总结&lt;/h2&gt;
&lt;p&gt;在这个过程中，我们看到了一家成熟的商业手机厂商，为了在极其有限的内存和苛刻的延迟要求下提供优秀的用户体验，所做出的教科书级别的架构设计：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;用 &lt;strong&gt;12-Bit 位移运算&lt;/strong&gt; 榨干最后一丝存储空间；&lt;/li&gt;
&lt;li&gt;用 &lt;strong&gt;墓碑机制与外挂补丁&lt;/strong&gt; 优雅解决行政区划合并的更新阵痛；&lt;/li&gt;
&lt;li&gt;用 &lt;strong&gt;多级指针与二分查找&lt;/strong&gt; 应对携号转网带来的规则崩塌。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;在如今 API 满天飞、算力过剩的时代，这种“锱铢必较”的底层工程美学，或许才是逆向分析带给我们的最大乐趣与收获。&lt;/p&gt;
</content:encoded></item><item><title>逆向解析 ColorOS 离线号码库 (二)：多级指针寻址的运营商识别与数据自愈</title><link>https://006lp.de/posts/reverse-coloros-offline-number-lookup/mnp-pointer-2/</link><guid isPermaLink="true">https://006lp.de/posts/reverse-coloros-offline-number-lookup/mnp-pointer-2/</guid><description>在 Part1 实现归属地查询的基础上，本节深入解析 ColorOS 运营商数据库的二进制结构：通过反编译还原「多级指针寻址」算法，实现号段到运营商的毫秒级映射；同时揭秘系统如何用&quot;墓碑机制&quot; + 外挂补丁动态修复区号合并导致的数据异常。最终整合归属地 + 运营商 + 区号自愈逻辑，输出纯 Python查询脚本。</description><pubDate>Sun, 22 Feb 2026 12:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;逆向解析 ColorOS 离线号码库 (二)：多级指针寻址的运营商识别与数据自愈&lt;/h1&gt;
&lt;h2&gt;0. 前言&lt;/h2&gt;
&lt;p&gt;在上一节中，我们成功逆向了号码归属地的 12-Bit 极限压缩算法。本节我们将继续深入，解析系统的运营商查询逻辑，并修复归属地查询中遗留的“异常区号”问题，最终实现一个归属地与运营商全息查询的完整脚本。&lt;/p&gt;
&lt;h2&gt;1. 架构分析：归属地与运营商的解耦&lt;/h2&gt;
&lt;p&gt;如果在归属地数据库（&lt;code&gt;PhoneNumberData_3_1_0.dat&lt;/code&gt;）中寻找运营商信息，结果会一无所获。在底层的架构设计中，归属地与运营商采用了两套完全不同的存储与匹配逻辑：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;归属地映射的离散性&lt;/strong&gt;：一个 &lt;code&gt;138&lt;/code&gt; 开头的号码，其归属地可能遍布全国各地（取决于号码中间 4 位）。这种离散性无法通过简单的公式计算，因此必须依赖体积达数 MB 的二进制字典树（Trie）进行硬映射。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;运营商分配的规律性&lt;/strong&gt;：在“携号转网”政策全面实施前，中国大陆的手机运营商是严格按前 3 位（或前 4 位）号段分配的（例如 &lt;code&gt;138&lt;/code&gt; 归属移动，&lt;code&gt;186&lt;/code&gt; 归属联通）。因此，将规律性极强的数据与庞大的归属地数据库分离，可以有效节省存储空间并提升查询效率。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;通过对代码的进一步反编译，我们定位到了两个专门处理运营商及特殊情况的文件：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;CarrierData_1_0.dat&lt;/code&gt;：体积较小，存储了基础的号段与运营商对应关系。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;PortabilityNumberData.dat&lt;/code&gt;：携号转网（MNP）数据库，用于修正发生转网的特殊号码。&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;2. 解析 CarrierData 数据结构&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;public final void q() throws IOException {
    File file = new File(f920p.getFilesDir(), &quot;CarrierData_1_0.dat&quot;);
    if (!file.exists()) {
        e.b(&quot;OplusCarrierManager&quot;, &quot;loadCarrierNameMap dataFile not exist&quot;);
        return;
    }
    DataInputStream dataInputStream = new DataInputStream(new FileInputStream(file));
    try {
        dataInputStream.skipBytes(16);
        int unsignedShort = dataInputStream.readUnsignedShort();
        for (int i3 = 0; i3 &amp;lt; unsignedShort; i3++) {
            int unsignedShort2 = dataInputStream.readUnsignedShort();
            String[] strArr = new String[4];
            for (int i4 = 0; i4 &amp;lt; 4; i4++) {
                strArr[i4] = BuildConfig.FLAVOR;
            }
            byte[] bArr = new byte[16];
            for (int i5 = 0; i5 &amp;lt; 4; i5++) {
                int unsignedShort3 = dataInputStream.readUnsignedShort();
                if (unsignedShort3 &amp;gt; 0) {
                    if (unsignedShort3 &amp;gt; bArr.length) {
                        bArr = new byte[unsignedShort3];
                    }
                    dataInputStream.readFully(bArr, 0, unsignedShort3);
                    strArr[i5] = new String(bArr, 0, unsignedShort3, l2.c.f761b);
                }
            }
            f917m.put(Integer.valueOf(unsignedShort2), strArr);
        }
        int unsignedShort4 = dataInputStream.readUnsignedShort();
        for (int i6 = 0; i6 &amp;lt; unsignedShort4; i6++) {
            int i7 = dataInputStream.readInt();
            int length = String.valueOf(i7).length();
            f914j = Math.max(length, f914j);
            f915k = Math.min(length, f915k);
            f913i.put(Integer.valueOf(i7), Integer.valueOf(dataInputStream.readUnsignedShort()));
        }
        int unsignedShort5 = dataInputStream.readUnsignedShort();
        for (int i8 = 0; i8 &amp;lt; unsignedShort5; i8++) {
            int i9 = dataInputStream.readInt();
            int length2 = String.valueOf(i9).length();
            f909e = Math.max(length2, f909e);
            f910f = Math.min(length2, f910f);
            f918n.put(Integer.valueOf(i9), Long.valueOf(dataInputStream.readInt()));
        }
        t1.k kVar = t1.k.f1147a;
        c2.a.a(dataInputStream, null);
        if (f906b) {
            e.a(&quot;OplusCarrierManager&quot;, &quot;carrierNumberNameMap：&quot;);
            for (Map.Entry&amp;lt;Integer, String[]&amp;gt; entry : f917m.entrySet()) {
                e.a(&quot;OplusCarrierManager&quot;, entry.getKey().intValue() + &quot; : &quot; + u1.j.l(entry.getValue()));
            }
            e.a(&quot;OplusCarrierManager&quot;, &quot;networkNumberFileOffsetMap：&quot; + f918n);
        }
        f911g = new ThreadLocal&amp;lt;&amp;gt;();
    } catch (Throwable th) {
        try {
            throw th;
        } catch (Throwable th2) {
            c2.a.a(dataInputStream, th);
            throw th2;
        }
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;通过反编译应用中的 &lt;code&gt;loadCarrierNameMap&lt;/code&gt;（即代码中的 &lt;code&gt;q()&lt;/code&gt; 方法），我们发现系统对运营商数据的存储采用了一套 &lt;strong&gt;“多级索引+内存偏移寻址”&lt;/strong&gt; 的二进制文件结构。&lt;/p&gt;
&lt;p&gt;根据 &lt;code&gt;DataInputStream&lt;/code&gt; 的顺序读取逻辑，该 &lt;code&gt;.dat&lt;/code&gt; 文件采用 &lt;strong&gt;大端序 (Big-Endian)&lt;/strong&gt; 存储，主要分为四大区域：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;文件头 (Header) - 16 字节&lt;/strong&gt;：包含版本号和 CRC32 校验码，代码中通过 &lt;code&gt;skipBytes(16)&lt;/code&gt; 直接跳过。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;运营商名称字典 (Carrier Names)&lt;/strong&gt;：首先读取运营商总数，随后依次读取对应的 ID 以及中文、英文、繁体台湾、繁体香港 4 个语言版本的名称（通过 &lt;code&gt;readUnsignedShort&lt;/code&gt; 获取字符串长度，再读取 UTF-8 字符串）。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;全局通用号段表 (General Prefixes)&lt;/strong&gt;：对应代码中的 &lt;code&gt;f913i&lt;/code&gt; 变量。存放前 3 位或前 4 位即可直接决定运营商的基础号段。数据结构为一个 32 位 Int（前缀）对应一个 16 位 Short（运营商 ID）。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;精细偏移映射表 (Detailed Offsets)&lt;/strong&gt;：对应代码中的 &lt;code&gt;f918n&lt;/code&gt; 变量。针对按万号段细分的复杂号码（如虚拟运营商），该表记录了号段前缀在文件底部的绝对字节偏移量 (Offset)。&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;2.1 双轨查询逻辑&lt;/h3&gt;
&lt;p&gt;在实际查询时，系统设计了两条路径：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;private final String t(String str, int i3) {
    int i4 = f909e;
    int i5 = f910f;
    if (i5 &amp;lt;= i4) {
        while (true) {
            String strSubstring = str.substring(0, i4);
            i.d(strSubstring, &quot;substring(...)&quot;);
            Long l3 = f918n.get(Integer.valueOf(Integer.parseInt(strSubstring)));
            if (l3 == null) {
                if (i4 == i5) {
                    break;
                }
                i4--;
            } else {
                String strSubstring2 = str.substring(i4, i4 + 4);
                i.d(strSubstring2, &quot;substring(...)&quot;);
                String strK = k(i3, strSubstring, strSubstring2);
                c&amp;lt;String, String&amp;gt; cVar = f916l;
                String strD = cVar.d(strK);
                if (strD != null) {
                    if (f906b) {
                        e.c(&quot;OplusCarrierManager&quot;, str + &quot; cache hit &quot;);
                    }
                    return strD;
                }
                String[] strArr = f917m.get(Integer.valueOf(r(Long.valueOf(l3.longValue() + ((long) (Integer.parseInt(strSubstring2) * 2))).longValue())));
                if (strArr == null) {
                    cVar.e(strK, BuildConfig.FLAVOR);
                    return null;
                }
                String str2 = (String) u1.j.h(strArr, i3);
                return TextUtils.isEmpty(str2) ? (String) u1.j.h(strArr, 0) : str2;
            }
        }
    }
    return null;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;精确路径 (&lt;code&gt;t()&lt;/code&gt; 方法)&lt;/strong&gt;：处理新号段或混合号段（如 &lt;code&gt;1705&lt;/code&gt; 虚拟运营商）。光匹配前几位并不足够，系统会查出前缀对应的底层偏移量，再加上号码中段数字计算出内存指针，直接跳转到文件尾部读取真实的运营商 ID。&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;private final String u(String str, int i3) {
    int i4 = f914j;
    int i5 = f915k;
    if (i5 &amp;lt;= i4) {        while (true) {
            String strSubstring = str.substring(0, i4);
            i.d(strSubstring, &quot;substring(...)&quot;);
            Integer num = f913i.get(Integer.valueOf(Integer.parseInt(strSubstring)));
            if (num == null) {
                if (i4 == i5) {
                    break;
                }
                i4--;
            } else {
                String[] strArr = f917m.get(num);
                if (strArr != null) {
                    return (String) u1.j.h(strArr, i3);
                }
                return null;
            }
        }
    }
    return null;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;快速路径 (&lt;code&gt;u()&lt;/code&gt; 方法)&lt;/strong&gt;：处理传统号段（如 &lt;code&gt;138&lt;/code&gt;）。前三位即可 100% 确定运营商，系统只需在 &lt;code&gt;general_prefixes&lt;/code&gt; 哈希表中查询一次即可迅速返回结果。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;2.3 Python 算法重构&lt;/h3&gt;
&lt;p&gt;基于以上的逆向分析，我们完全脱离了 Android 环境，使用纯 Python 实现了对该二进制数据文件的脱机解析与查询。完整代码如下：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;import os
import struct

def load_carrier_database(file_path):
    print(&quot;⏳ 正在加载并解析运营商底层数据库...&quot;)
    with open(file_path, &apos;rb&apos;) as f:
        data = f.read()

    offset = 16  # dataInputStream.skipBytes(16)

    # 1. 读取运营商名称字典
    carrier_names = {}
    num_carriers = struct.unpack_from(&quot;&amp;gt;H&quot;, data, offset)[0]
    offset += 2
    
    for _ in range(num_carriers):
        carrier_id = struct.unpack_from(&quot;&amp;gt;H&quot;, data, offset)[0]
        offset += 2
        
        names = []
        # 依次读取 中文、英文、繁体台湾、繁体香港 4 个语言版本
        for _ in range(4):
            str_len = struct.unpack_from(&quot;&amp;gt;H&quot;, data, offset)[0]
            offset += 2
            if str_len &amp;gt; 0:
                # UTF-8 解码字符串
                name = data[offset : offset + str_len].decode(&apos;utf-8&apos;, errors=&apos;ignore&apos;)
                offset += str_len
            else:
                name = &quot;&quot;
            names.append(name)
            
        carrier_names[carrier_id] = names

    # 2. 读取全局通用号段表 (f913i)
    general_prefixes = {}
    num_gen_prefixes = struct.unpack_from(&quot;&amp;gt;H&quot;, data, offset)[0]
    offset += 2
    
    for _ in range(num_gen_prefixes):
        prefix_val = struct.unpack_from(&quot;&amp;gt;i&quot;, data, offset)[0]
        offset += 4
        cid = struct.unpack_from(&quot;&amp;gt;H&quot;, data, offset)[0]
        offset += 2
        general_prefixes[str(prefix_val)] = cid

    # 3. 读取精细偏移映射表 (f918n)
    detailed_prefixes = {}
    num_det_prefixes = struct.unpack_from(&quot;&amp;gt;H&quot;, data, offset)[0]
    offset += 2
    
    for _ in range(num_det_prefixes):
        prefix_val = struct.unpack_from(&quot;&amp;gt;i&quot;, data, offset)[0]
        offset += 4
        file_offset = struct.unpack_from(&quot;&amp;gt;i&quot;, data, offset)[0]
        offset += 4
        detailed_prefixes[str(prefix_val)] = file_offset

    print(f&quot;✅ 成功解析: {len(carrier_names)} 个运营商, {len(general_prefixes)} 个全局号段, {len(detailed_prefixes)} 个精细号段偏移&quot;)
    
    return data, carrier_names, general_prefixes, detailed_prefixes

def query_carrier(phone, data, carrier_names, general_prefixes, detailed_prefixes):
    if len(phone) &amp;lt; 7 or not phone.isdigit():
        return &quot;❌ 请输入至少 7 位数字号码&quot;

    # 还原代码中的 t() 方法：优先匹配精细偏移映射
    # 动态尝试长度 4 和 3 (反编译代码里的 f909e 到 f910f)
    for length in range(4, 2, -1):
        prefix = phone[:length]
        if prefix in detailed_prefixes:
            suffix = phone[length : length+4]
            if len(suffix) == 4:
                # 计算文件底部的绝对寻址: Offset + int(suffix) * 2 bytes
                target_offset = detailed_prefixes[prefix] + (int(suffix) * 2)
                if target_offset + 2 &amp;lt;= len(data):
                    cid = struct.unpack_from(&quot;&amp;gt;H&quot;, data, target_offset)[0]
                    if cid in carrier_names:
                        # 返回索引 0 的中文名称
                        name = carrier_names[cid][0] 
                        return name if name else carrier_names[cid][1]

    # 还原代码中的 u() 方法：匹配全局通用号段
    for length in range(4, 2, -1):
        prefix = phone[:length]
        if prefix in general_prefixes:
            cid = general_prefixes[prefix]
            if cid in carrier_names:
                name = carrier_names[cid][0]
                return name if name else carrier_names[cid][1]

    return &quot;未知运营商&quot;

def main():
    file_name = &quot;CarrierData_1_0.dat&quot;
    if not os.path.exists(file_name):
        print(f&quot;❌ 找不到文件：{file_name}，请确保与脚本同目录。&quot;)
        return

    data, carrier_names, general_prefixes, detailed_prefixes = load_carrier_database(file_name)

    print(&quot;\n&quot; + &quot;=&quot;*40)
    print(&quot;📡 OPPO 底层运营商查询系统&quot;)
    print(&quot;=&quot;*40)
    
    while True:
        try:
            user_input = input(&quot;\n👉 请输入 7位及以上手机号 (输入 q 退出): &quot;).strip()
            if user_input.lower() == &apos;q&apos;:
                break
                
            carrier = query_carrier(user_input, data, carrier_names, general_prefixes, detailed_prefixes)
            print(f&quot;🏢 运营商: 【{carrier}】&quot;)
            
        except KeyboardInterrupt:
            break
        except Exception as e:
            print(f&quot;发生错误: {e}&quot;)
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;3. 修复长途区号 “9999” 的墓碑机制&lt;/h2&gt;
&lt;p&gt;在初步运行上一节的归属地查询脚本时，部分地区的归属地虽然正确，但长途区号会异常显示为 &lt;code&gt;9999&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;这一现象源于近年来中国部分省份的行政区划调整和长途区号合并。例如：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;广西南宁与崇左合并了区号 &lt;code&gt;0771&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;四川成都、眉山、资阳合并了区号 &lt;code&gt;028&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;辽宁沈阳、抚顺、铁岭合并了区号 &lt;code&gt;024&lt;/code&gt;。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;为了避免重新生成并下发数 MB 的底层二进制结构，工程师采用了一种巧妙的 &lt;strong&gt;“墓碑机制 (Tombstone)”&lt;/strong&gt; ：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;将原有的老条目（如独立的“广西南宁”）区号修改为 &lt;code&gt;9999&lt;/code&gt;，作为废弃标记。&lt;/li&gt;
&lt;li&gt;在城市字典列表的末尾，追加新的合并城市名（如 &lt;code&gt;0771 广西南宁/崇左&lt;/code&gt;）。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;同时，系统引入了一个外挂补丁文件 &lt;code&gt;Multi_Areano_Table.txt&lt;/code&gt;。该文件记录了新旧数据的映射关系：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;origin_id	cityname	equal_id	equal_cityname
10	辽宁沈阳	379	辽宁沈阳/抚顺/铁岭
13	四川成都	378	四川成都/眉山/资阳
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;遗憾的是，当试图查看最核心的重定向方法 &lt;code&gt;h()&lt;/code&gt;  时，Jadx 再次放弃了转换。无奈之下，只能继续硬着头皮去阅读底层的 &lt;strong&gt;Smali 汇编指令&lt;/strong&gt;。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;.method public h(Landroid/database/sqlite/SQLiteDatabase;)V
    .registers 11

    .line 1
    const-string v0, &quot;PhoneNoDbHelper&quot;

    .line 2
    .line 3
    const/4 v1, 0x0

    .line 4
    :try_start_3
    iget-object p0, p0, Ll0/d;-&amp;gt;d:Landroid/content/Context;

    .line 5
    .line 6
    invoke-virtual {p0}, Landroid/content/Context;-&amp;gt;getAssets()Landroid/content/res/AssetManager;

    .line 7
    .line 8
    .line 9
    move-result-object p0

    .line 10
    const-string v2, &quot;Multi_Areano_Table.txt&quot;

    .line 11
    .line 12
    invoke-virtual {p0, v2}, Landroid/content/res/AssetManager;-&amp;gt;open(Ljava/lang/String;)Ljava/io/InputStream;

    .line 13
    .line 14
    .line 15
    move-result-object p0
    :try_end_f
    .catch Ljava/lang/Exception; {:try_start_3 .. :try_end_f} :catch_a3
    .catchall {:try_start_3 .. :try_end_f} :catchall_a0

    .line 16
    if-eqz p0, :cond_8e

    .line 17
    .line 18
    if-nez p1, :cond_15

    .line 19
    .line 20
    goto/16 :goto_8e

    .line 21
    .line 22
    :cond_15
    :try_start_15
    invoke-static {}, Landroid/os/SystemClock;-&amp;gt;elapsedRealtime()J

    .line 23
    .line 24
    .line 25
    move-result-wide v2

    .line 26
    new-instance v4, Ljava/io/BufferedReader;

    .line 27
    .line 28
    new-instance v5, Ljava/io/InputStreamReader;

    .line 29
    .line 30
    invoke-direct {v5, p0}, Ljava/io/InputStreamReader;-&amp;gt;&amp;lt;init&amp;gt;(Ljava/io/InputStream;)V

    .line 31
    .line 32
    .line 33
    invoke-direct {v4, v5}, Ljava/io/BufferedReader;-&amp;gt;&amp;lt;init&amp;gt;(Ljava/io/Reader;)V
    :try_end_23
    .catch Ljava/lang/Exception; {:try_start_15 .. :try_end_23} :catch_9d
    .catchall {:try_start_15 .. :try_end_23} :catchall_99

    .line 34
    .line 35
    .line 36
    const/4 v1, 0x1

    .line 37
    :cond_24
    :goto_24
    :try_start_24
    invoke-virtual {v4}, Ljava/io/BufferedReader;-&amp;gt;readLine()Ljava/lang/String;

    .line 38
    .line 39
    .line 40
    move-result-object v5

    .line 41
    invoke-static {v5}, Landroid/text/TextUtils;-&amp;gt;isEmpty(Ljava/lang/CharSequence;)Z

    .line 42
    .line 43
    .line 44
    move-result v6

    .line 45
    if-eqz v6, :cond_2f

    .line 46
    .line 47
    goto :goto_39

    .line 48
    :cond_2f
    invoke-virtual {v5}, Ljava/lang/String;-&amp;gt;trim()Ljava/lang/String;

    .line 49
    .line 50
    .line 51
    move-result-object v5

    .line 52
    invoke-static {v5}, Landroid/text/TextUtils;-&amp;gt;isEmpty(Ljava/lang/CharSequence;)Z

    .line 53
    .line 54
    .line 55
    move-result v6

    .line 56
    if-eqz v6, :cond_56

    .line 57
    .line 58
    :goto_39
    new-instance p1, Ljava/lang/StringBuilder;

    .line 59
    .line 60
    invoke-direct {p1}, Ljava/lang/StringBuilder;-&amp;gt;&amp;lt;init&amp;gt;()V

    .line 61
    .line 62
    .line 63
    const-string v1, &quot;updateCityCode use &quot;

    .line 64
    .line 65
    invoke-virtual {p1, v1}, Ljava/lang/StringBuilder;-&amp;gt;append(Ljava/lang/String;)Ljava/lang/StringBuilder;

    .line 66
    .line 67
    .line 68
    invoke-static {}, Landroid/os/SystemClock;-&amp;gt;elapsedRealtime()J

    .line 69
    .line 70
    .line 71
    move-result-wide v5

    .line 72
    sub-long/2addr v5, v2

    .line 73
    invoke-virtual {p1, v5, v6}, Ljava/lang/StringBuilder;-&amp;gt;append(J)Ljava/lang/StringBuilder;

    .line 74
    .line 75
    .line 76
    invoke-virtual {p1}, Ljava/lang/StringBuilder;-&amp;gt;toString()Ljava/lang/String;

    .line 77
    .line 78
    .line 79
    move-result-object p1

    .line 80
    invoke-static {v0, p1}, Landroid/util/Log;-&amp;gt;d(Ljava/lang/String;Ljava/lang/String;)I
    :try_end_52
    .catch Ljava/lang/Exception; {:try_start_24 .. :try_end_52} :catch_9e
    .catchall {:try_start_24 .. :try_end_52} :catchall_8c

    .line 81
    .line 82
    .line 83
    invoke-virtual {p0}, Ljava/io/InputStream;-&amp;gt;close()V

    .line 84
    .line 85
    .line 86
    goto :goto_b0

    .line 87
    :cond_56
    const/4 v6, 0x0

    .line 88
    if-eqz v1, :cond_5b

    .line 89
    .line 90
    move v1, v6

    .line 91
    goto :goto_24

    .line 92
    :cond_5b
    :try_start_5b
    const-string v7, &quot;\t&quot;

    .line 93
    .line 94
    invoke-virtual {v5, v7}, Ljava/lang/String;-&amp;gt;split(Ljava/lang/String;)[Ljava/lang/String;

    .line 95
    .line 96
    .line 97
    move-result-object v5

    .line 98
    array-length v7, v5

    .line 99
    const/4 v8, 0x4

    .line 100
    if-ne v7, v8, :cond_24

    .line 101
    .line 102
    new-instance v7, Ljava/lang/StringBuilder;

    .line 103
    .line 104
    invoke-direct {v7}, Ljava/lang/StringBuilder;-&amp;gt;&amp;lt;init&amp;gt;()V

    .line 105
    .line 106
    .line 107
    const-string v8, &quot;UPDATE areano_and_citynames SET equal_id = \&apos;&quot;

    .line 108
    .line 109
    invoke-virtual {v7, v8}, Ljava/lang/StringBuilder;-&amp;gt;append(Ljava/lang/String;)Ljava/lang/StringBuilder;

    .line 110
    .line 111
    .line 112
    const/4 v8, 0x2

    .line 113
    aget-object v8, v5, v8

    .line 114
    .line 115
    invoke-virtual {v7, v8}, Ljava/lang/StringBuilder;-&amp;gt;append(Ljava/lang/String;)Ljava/lang/StringBuilder;

    .line 116
    .line 117
    .line 118
    const-string v8, &quot;\&apos; WHERE _id = \&apos;&quot;

    .line 119
    .line 120
    invoke-virtual {v7, v8}, Ljava/lang/StringBuilder;-&amp;gt;append(Ljava/lang/String;)Ljava/lang/StringBuilder;

    .line 121
    .line 122
    .line 123
    aget-object v5, v5, v6

    .line 124
    .line 125
    invoke-virtual {v7, v5}, Ljava/lang/StringBuilder;-&amp;gt;append(Ljava/lang/String;)Ljava/lang/StringBuilder;

    .line 126
    .line 127
    .line 128
    const-string v5, &quot;\&apos;;&quot;

    .line 129
    .line 130
    invoke-virtual {v7, v5}, Ljava/lang/StringBuilder;-&amp;gt;append(Ljava/lang/String;)Ljava/lang/StringBuilder;

    .line 131
    .line 132
    .line 133
    invoke-virtual {v7}, Ljava/lang/StringBuilder;-&amp;gt;toString()Ljava/lang/String;

    .line 134
    .line 135
    .line 136
    move-result-object v5

    .line 137
    invoke-virtual {p1, v5}, Landroid/database/sqlite/SQLiteDatabase;-&amp;gt;execSQL(Ljava/lang/String;)V
    :try_end_8b
    .catch Ljava/lang/Exception; {:try_start_5b .. :try_end_8b} :catch_9e
    .catchall {:try_start_5b .. :try_end_8b} :catchall_8c

    .line 138
    .line 139
    .line 140
    goto :goto_24

    .line 141
    :catchall_8c
    move-exception p1

    .line 142
    goto :goto_9b

    .line 143
    :cond_8e
    :goto_8e
    :try_start_8e
    const-string p1, &quot;updateCityCode inputStream or db is null&quot;

    .line 144
    .line 145
    invoke-static {v0, p1}, Landroid/util/Log;-&amp;gt;d(Ljava/lang/String;Ljava/lang/String;)I
    :try_end_93
    .catch Ljava/lang/Exception; {:try_start_8e .. :try_end_93} :catch_9d
    .catchall {:try_start_8e .. :try_end_93} :catchall_99

    .line 146
    .line 147
    .line 148
    if-eqz p0, :cond_98

    .line 149
    .line 150
    invoke-virtual {p0}, Ljava/io/InputStream;-&amp;gt;close()V

    .line 151
    .line 152
    .line 153
    :cond_98
    return-void

    .line 154
    :catchall_99
    move-exception p1

    .line 155
    move-object v4, v1

    .line 156
    :goto_9b
    move-object v1, p0

    .line 157
    goto :goto_b5

    .line 158
    :catch_9d
    move-object v4, v1

    .line 159
    :catch_9e
    move-object v1, p0

    .line 160
    goto :goto_a4

    .line 161
    :catchall_a0
    move-exception p1

    .line 162
    move-object v4, v1

    .line 163
    goto :goto_b5

    .line 164
    :catch_a3
    move-object v4, v1

    .line 165
    :goto_a4
    :try_start_a4
    const-string p0, &quot;update city code error&quot;

    .line 166
    .line 167
    invoke-static {v0, p0}, Landroid/util/Log;-&amp;gt;e(Ljava/lang/String;Ljava/lang/String;)I
    :try_end_a9
    .catchall {:try_start_a4 .. :try_end_a9} :catchall_b4

    .line 168
    .line 169
    .line 170
    if-eqz v1, :cond_ae

    .line 171
    .line 172
    invoke-virtual {v1}, Ljava/io/InputStream;-&amp;gt;close()V

    .line 173
    .line 174
    .line 175
    :cond_ae
    if-eqz v4, :cond_b3

    .line 176
    .line 177
    :goto_b0
    invoke-virtual {v4}, Ljava/io/BufferedReader;-&amp;gt;close()V

    .line 178
    .line 179
    .line 180
    :cond_b3
    return-void

    .line 181
    :catchall_b4
    move-exception p1

    .line 182
    :goto_b5
    if-eqz v1, :cond_ba

    .line 183
    .line 184
    invoke-virtual {v1}, Ljava/io/InputStream;-&amp;gt;close()V

    .line 185
    .line 186
    .line 187
    :cond_ba
    if-eqz v4, :cond_bf

    .line 188
    .line 189
    invoke-virtual {v4}, Ljava/io/BufferedReader;-&amp;gt;close()V

    .line 190
    .line 191
    .line 192
    :cond_bf
    throw p1
.end method
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;在对应的 Smali 代码中，系统在初始化 SQLite 数据库时执行了类似如下的重定向操作：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;-- 省略部分逻辑
UPDATE areano_and_citynames SET equal_id = &apos;379&apos; WHERE _id = &apos;10&apos;;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这意味着，当底层解密算出号码属于旧的 &lt;code&gt;id = 10&lt;/code&gt; 时，系统会通过重定向直接获取 &lt;code&gt;id = 379&lt;/code&gt; 的合并后数据。&lt;/p&gt;
&lt;h2&gt;4. 全息解析 Python 脚本整合&lt;/h2&gt;
&lt;p&gt;结合以上两节的分析，我们将官方的 &lt;code&gt;Multi_Areano_Table.txt&lt;/code&gt; 补丁动态加载至内存，并融合了多级指针寻址的运营商识别机制，实现了归属地与运营商的“二合一”查询。&lt;/p&gt;
&lt;p&gt;以下是完整的 Python 实现代码：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;import os
import struct

# ==========================================
# 模块 1：归属地数据库解析 (PhoneNumberData)
# ==========================================
def load_location_db(file_path):
    print(&quot;⏳ [1/2] 正在加载 归属地 数据库...&quot;)
    with open(file_path, &apos;rb&apos;) as f:
        data = f.read()

    tail_data = data[-12002:]
    area_codes_raw = tail_data[2:2002]
    city_names_raw = tail_data[2002:10002]
    extend_prefix_raw = tail_data[10002:12002]

    cities = []
    for i in range(400):
        area = area_codes_raw[i*5 : i*5+5].decode(&apos;ascii&apos;, errors=&apos;ignore&apos;).strip()
        name_bytes = city_names_raw[i*20 : i*20+20].split(b&apos;\x00&apos;)[0]
        name = name_bytes.decode(&apos;gbk&apos;, errors=&apos;ignore&apos;).strip()
        cities.append([area, name]) 

    # 🌟 官方补丁外挂：动态加载 Multi_Areano_Table.txt 处理重定向
    patch_file = &quot;Multi_Areano_Table.txt&quot;
    if os.path.exists(patch_file):
        print(&quot;   -&amp;gt; 发现官方区号修正补丁，正在进行数据合并重定向...&quot;)
        with open(patch_file, &quot;r&quot;, encoding=&quot;utf-8&quot;) as f:
            lines = f.readlines()
            for line in lines[1:]:  # 跳过表头
                parts = line.strip().split(&apos;\t&apos;)
                if len(parts) == 4:
                    origin_id = int(parts[0])
                    equal_id = int(parts[2])
                    
                    # 数据库 _id 从 1 开始，数组索引需减 1
                    target_area, target_name = cities[equal_id - 1]
                    # 覆盖旧的 9999 废弃数据
                    cities[origin_id - 1][0] = target_area
    else:
        print(f&quot;   -&amp;gt; ⚠️ 未找到 {patch_file}，部分合并城市的区号可能显示为 9999。&quot;)

    # 构建号段偏移映射表
    prefix_map = {}
    base_idx = 0
    for p in range(130, 140): prefix_map[str(p)] = base_idx; base_idx += 10000
    for p in range(150, 160): prefix_map[str(p)] = base_idx; base_idx += 10000
    prefix_map[&quot;188&quot;] = base_idx; base_idx += 10000
    prefix_map[&quot;189&quot;] = base_idx; base_idx += 10000

    for i in range(1000):
        b1 = extend_prefix_raw[i*2]
        b2 = extend_prefix_raw[i*2 + 1]
        prefix_val = (b1 &amp;lt;&amp;lt; 8) | b2
        if prefix_val == 0: break
        prefix_map[str(prefix_val)] = base_idx
        base_idx += 10000

    binary_array = data[16 : -12002]
    print(f&quot;✅ [1/2] 归属地加载成功！(解析号段数: {len(prefix_map)})&quot;)
    
    return prefix_map, cities, binary_array

# ==========================================
# 模块 2：运营商数据库解析 (CarrierData)
# ==========================================
def load_carrier_db(file_path):
    print(&quot;⏳ [2/2] 正在加载 运营商 数据库...&quot;)
    with open(file_path, &apos;rb&apos;) as f:
        data = f.read()

    offset = 16 
    
    # 1. 解析运营商名称字典
    carrier_names = {}
    num_carriers = struct.unpack_from(&quot;&amp;gt;H&quot;, data, offset)[0]
    offset += 2
    for _ in range(num_carriers):
        carrier_id = struct.unpack_from(&quot;&amp;gt;H&quot;, data, offset)[0]
        offset += 2
        names = []
        for _ in range(4):
            str_len = struct.unpack_from(&quot;&amp;gt;H&quot;, data, offset)[0]
            offset += 2
            if str_len &amp;gt; 0:
                name = data[offset : offset + str_len].decode(&apos;utf-8&apos;, errors=&apos;ignore&apos;)
                offset += str_len
            else:
                name = &quot;&quot;
            names.append(name)
        carrier_names[carrier_id] = names

    # 2. 解析全局通用号段表
    general_prefixes = {}
    num_gen_prefixes = struct.unpack_from(&quot;&amp;gt;H&quot;, data, offset)[0]
    offset += 2
    for _ in range(num_gen_prefixes):
        prefix_val = struct.unpack_from(&quot;&amp;gt;i&quot;, data, offset)[0]
        offset += 4
        cid = struct.unpack_from(&quot;&amp;gt;H&quot;, data, offset)[0]
        offset += 2
        general_prefixes[str(prefix_val)] = cid

    # 3. 解析精细偏移映射表
    detailed_prefixes = {}
    num_det_prefixes = struct.unpack_from(&quot;&amp;gt;H&quot;, data, offset)[0]
    offset += 2
    for _ in range(num_det_prefixes):
        prefix_val = struct.unpack_from(&quot;&amp;gt;i&quot;, data, offset)[0]
        offset += 4
        file_offset = struct.unpack_from(&quot;&amp;gt;i&quot;, data, offset)[0]
        offset += 4
        detailed_prefixes[str(prefix_val)] = file_offset

    print(f&quot;✅ [2/2] 运营商加载成功！(精细号段规则: {len(detailed_prefixes)}条)&quot;)
    return data, carrier_names, general_prefixes, detailed_prefixes

# ==========================================
# 模块 3：全息信息统一查询接口
# ==========================================
def query_phone_info(phone, loc_data, car_data):
    if len(phone) &amp;lt; 7 or not phone.isdigit():
        return &quot;❌ 格式错误：请输入至少 7 位纯数字号码！&quot;

    eval_phone = phone[:8] 
    phone_7 = eval_phone[:7]
    
    # --- A. 归属地查询逻辑 (12-Bit 压缩解密) ---
    prefix_map, cities, binary_array = loc_data
    prefix = phone_7[:3]
    suffix = phone_7[3:]
    
    loc_name = &quot;未知&quot;
    area_code = &quot;未知&quot;
    
    if prefix in prefix_map:
        absolute_index = prefix_map[prefix] + int(suffix)
        byte_offset = (absolute_index // 2) * 3
        
        if byte_offset + 2 &amp;lt; len(binary_array):
            b1 = binary_array[byte_offset]
            b2 = binary_array[byte_offset + 1]
            b3 = binary_array[byte_offset + 2]
            
            if absolute_index % 2 == 0:
                city_id = (b1 &amp;lt;&amp;lt; 4) | (b2 &amp;gt;&amp;gt; 4)
            else:
                city_id = ((b2 &amp;amp; 0x0F) &amp;lt;&amp;lt; 8) | b3
                
            if city_id != 0 and city_id &amp;lt; len(cities):
                area_code, loc_name = cities[city_id]
                if not loc_name: loc_name = &quot;未知&quot;

    # --- B. 运营商查询逻辑 (多级指针寻址) ---
    car_raw_data, carrier_names, general_prefixes, detailed_prefixes = car_data
    carrier_name = &quot;未知运营商&quot;
    found_carrier = False

    # B.1 优先进行精细规则匹配
    for length in range(4, 2, -1):
        p_prefix = eval_phone[:length]
        if p_prefix in detailed_prefixes:
            p_suffix = eval_phone[length : length+4]
            if len(p_suffix) == 4:
                target_offset = detailed_prefixes[p_prefix] + (int(p_suffix) * 2)
                if target_offset + 2 &amp;lt;= len(car_raw_data):
                    cid = struct.unpack_from(&quot;&amp;gt;H&quot;, car_raw_data, target_offset)[0]
                    if cid in carrier_names:
                        carrier_name = carrier_names[cid][0] or carrier_names[cid][1]
                        found_carrier = True
                        break

    # B.2 若未命中，则进行全局大号段匹配
    if not found_carrier:
        for length in range(4, 2, -1):
            p_prefix = eval_phone[:length]
            if p_prefix in general_prefixes:
                cid = general_prefixes[p_prefix]
                if cid in carrier_names:
                    carrier_name = carrier_names[cid][0] or carrier_names[cid][1]
                    break

    result = (
        f&quot;📱 查询号码: {phone}\n&quot;
        f&quot;📍 归属地点: 【{loc_name}】 (长途区号: {area_code})\n&quot;
        f&quot;🏢 运营网络: 【{carrier_name}】&quot;
    )
    return result

def main():
    print(&quot;=&quot; * 45)
    print(&quot;🚀 ColorOS 离线号码全息识别系统&quot;)
    print(&quot;=&quot; * 45)
    
    loc_file = &quot;PhoneNumberData_3_1_0.dat&quot;
    car_file = &quot;CarrierData_1_0.dat&quot;
    
    if not os.path.exists(loc_file) or not os.path.exists(car_file):
        print(f&quot;❌ 启动失败：缺少数据库文件。\n请确保 {loc_file} 和 {car_file} 都在同一目录！&quot;)
        return

    loc_data = load_location_db(loc_file)
    car_data = load_carrier_db(car_file)
    print(&quot;-&quot; * 45)

    while True:
        try:
            user_input = input(&quot;\n👉 请输入完整的手机号 (输入 q 退出): &quot;).strip()
            if user_input.lower() == &apos;q&apos;:
                print(&quot;👋 系统已退出。&quot;)
                break
                
            result = query_phone_info(user_input, loc_data, car_data)
            print(&quot;-&quot; * 35)
            print(result)
            print(&quot;-&quot; * 35)
            
        except KeyboardInterrupt:
            print(&quot;\n👋 系统已退出。&quot;)
            break
        except Exception as e:
            print(f&quot;⚠️ 查询中发生异常: {e}&quot;)
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;5. 小结&lt;/h2&gt;
&lt;p&gt;至此，我们已经成功提取并重构了基于号码前 7 位的归属地与运营商查询逻辑。但对于发生过“携号转网”的特例号码，传统的号段查询便会失效。在下一节中，我们将解析 &lt;code&gt;PortabilityNumberData.dat&lt;/code&gt; 特权库，探究系统是如何利用二分查找算法解决携号转网难题的，并最终实现支持高并发的数据全量导出脚本。&lt;/p&gt;
</content:encoded></item><item><title>逆向解析 ColorOS 离线号码库 (一)：12-Bit 极限压缩的归属地查询算法</title><link>https://006lp.de/posts/reverse-coloros-offline-number-lookup/12bit-phone-number-compression-1/</link><guid isPermaLink="true">https://006lp.de/posts/reverse-coloros-offline-number-lookup/12bit-phone-number-compression-1/</guid><description>逆向解析 ColorOS 离线号码库：通过静态分析 APK 与 Smali 汇编，还原 12-Bit 极限压缩算法，实现无网络手机号归属地查询。附完整 Python 重构代码，脱离 Android 环境即可运行。</description><pubDate>Sat, 21 Feb 2026 21:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;逆向解析 ColorOS 离线号码库 (一)：12-Bit 极限压缩的归属地查询算法&lt;/h1&gt;
&lt;h2&gt;0. 前言&lt;/h2&gt;
&lt;p&gt;最近在开发一个项目时，需要用到中国大陆电话号码归属地以及运营商查询的 API。在调研了网络上现有的 API 后，我发现它们要么存在严格的并发限制和 API Key 双重校验，要么底层的数据库不够完整和准确。&lt;/p&gt;
&lt;p&gt;但我们平时使用的智能手机，在没有网络的情况下依然能在来电几毫秒内准确显示号码归属地，它们是如何做到的？与其依赖受限的网络 API，不如直接从手机系统自带的拨号软件中提取离线数据库。&lt;/p&gt;
&lt;h2&gt;1. 理论依据与通用架构&lt;/h2&gt;
&lt;p&gt;在原生的 Android 系统中，来电归属地等本土化功能其实比较薄弱。但国内的手机厂商（如 OPPO、小米、vivo 等）都基于此构建了一套非常成熟的 &lt;strong&gt;“本地离线查询 + 云端辅助”&lt;/strong&gt; 机制。&lt;/p&gt;
&lt;p&gt;这类系统实现“归属地与运营商”查找的通用技术架构一般如下：&lt;/p&gt;
&lt;p&gt;a. &lt;strong&gt;核心原理：基于“号段”的离线映射&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;中国大陆的手机号码分配有着严格的规律。通常，前 3 位决定了基础运营商，而前 7 位决定了具体的地级市归属地和运营商细分。厂商会在系统级的核心应用（如 &lt;code&gt;ContactsProvider.apk&lt;/code&gt; 或独立的 &lt;code&gt;Telephony&lt;/code&gt; 服务）中内置一个高度压缩的离线数据库（通常是 &lt;code&gt;.db&lt;/code&gt;、&lt;code&gt;.dat&lt;/code&gt; 格式或自定义的二进制文件）。&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;号段示例 (前7位)&lt;/th&gt;
&lt;th&gt;运营商&lt;/th&gt;
&lt;th&gt;归属地&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;138 0010&lt;/td&gt;
&lt;td&gt;中国移动&lt;/td&gt;
&lt;td&gt;北京&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;186 0210&lt;/td&gt;
&lt;td&gt;中国联通&lt;/td&gt;
&lt;td&gt;上海&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;189 0200&lt;/td&gt;
&lt;td&gt;中国电信&lt;/td&gt;
&lt;td&gt;天津&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;b. &lt;strong&gt;代码层面的查询流程&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;当我们在拨号盘输入号码，或者收到来电时，系统的跨进程查询流程通常如下：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;提取特征&lt;/strong&gt;：系统前端首先清洗输入的号码（去除 &lt;code&gt;+86&lt;/code&gt;、空格、破折号等格式字符），然后截取前 7 位核心号段。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;IPC 跨进程通信&lt;/strong&gt;：UI 层不会直接去读取底层离线文件，而是通过构建特定的 &lt;code&gt;Uri&lt;/code&gt;，向系统的底层内容提供者（&lt;code&gt;ContentProvider&lt;/code&gt;）发起查询请求。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;底层解析返回&lt;/strong&gt;：底层的服务应用接收到请求后，通过查表或特定算法解析二进制数据文件，将计算出的“归属地”和“运营商”字段打包，原路返回给 UI 层进行渲染显示。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;2. 寻找并定位离线数据库&lt;/h2&gt;
&lt;p&gt;以我所使用的设备 &lt;strong&gt;OPPO Find X6（ColorOS 16.0 系统）&lt;/strong&gt; 为例。&lt;/p&gt;
&lt;p&gt;通过在系统中进行关键词检索，我很快定位到了专门负责处理归属地逻辑的系统应用——&lt;strong&gt;号码归属地&lt;/strong&gt; (&lt;code&gt;com.oplus.phonenoareainquire&lt;/code&gt;)。幸运的是，作为系统内建的基础服务，该应用并未进行深度的加固或高强度混淆，这为我们的静态分析提供了极大的便利。&lt;/p&gt;
&lt;p&gt;提取并解压该应用的 APK 文件后，在 &lt;code&gt;/assets&lt;/code&gt; 目录下，我如愿以偿地找到了两个核心数据文件：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;PhoneNumberData_3_1_0.dat&lt;/code&gt; (归属地数据库)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;CarrierData_1_0.dat&lt;/code&gt; (运营商数据库)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;本节我们先将目光聚焦在归属地文件 &lt;code&gt;PhoneNumberData_3_1_0.dat&lt;/code&gt; 上。&lt;/p&gt;
&lt;p&gt;不出所料，使用普通的文本编辑器打开它后是一堆乱码。为了让系统在极短的时间内完成检索，厂商并没有使用纯文本或标准的 SQLite 格式，而是采用了一种自定义的高强度压缩二进制数据结构。&lt;/p&gt;
&lt;p&gt;不过，通过分析文件底层的字节流，我们依然能窥探到一些明文线索：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;文件头 (Header)&lt;/strong&gt;：文件最开头明文存储了一串数字 &lt;code&gt;817820250424&lt;/code&gt;。在大多数安卓号段库中，这通常代表着数据库的版本号或最后更新的编译时间戳。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;数据字典区 (Tail)&lt;/strong&gt;：在文件靠后的尾部数据区，清晰地暴露出了中国大陆的城市长途区号及地名（采用 GBK 编码）。例如：&lt;code&gt;010&lt;/code&gt;、&lt;code&gt;020&lt;/code&gt;、&lt;code&gt;021&lt;/code&gt;（分别对应北京、广州、上海），以及成百上千个地级市的区号。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;3. 提取读取规则与字典表&lt;/h2&gt;
&lt;p&gt;既然无法直接阅读，那没招了，试试 &lt;strong&gt;Jadx&lt;/strong&gt; 逆向吧。&lt;/p&gt;
&lt;p&gt;在 Jadx 中全局搜索字符串 &lt;code&gt;&quot;PhoneNumberData_3_1_0.dat&quot;&lt;/code&gt;，很快定位到了负责初始化的 &lt;code&gt;PhoneNoInquireDatabaseHelper.java&lt;/code&gt; 类。在它的 &lt;code&gt;c()&lt;/code&gt; 方法中，揭示了文件头部的读取规则：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;public void c(SQLiteDatabase sQLiteDatabase, String str) throws Throwable {
    File fileA = b.a(PhoneNoInquireProvider.f300w);
    InputStream inputStreamOpen = this.f740d.getResources().getAssets().open(&quot;PhoneNumberData_3_1_0.dat&quot;);
    FileOutputStream fileOutputStream = new FileOutputStream(fileA);
    byte[] bArr = new byte[102400];
    Log.i(&quot;PhoneNoDbHelper&quot;, &quot;copy PhoneNumberData.dat to /data/data/&quot;);
    while (true) {
        int i3 = inputStreamOpen.read(bArr);
        if (i3 == -1) {
            break;
        } else {
            fileOutputStream.write(bArr, 0, i3);
        }
    }
    inputStreamOpen.close();
    fileOutputStream.close();
    FileInputStream fileInputStream = new FileInputStream(fileA);
    DataInputStream dataInputStream = new DataInputStream(a(fileInputStream));
    byte[] bArr2 = new byte[12]; // 读取前 12 个字节作为版本号
    int i4 = dataInputStream.read(bArr2, 0, 12);
    String str2 = new String(bArr2, &quot;UTF-8&quot;); // 对应我们看到的 817820250424
    Log.i(&quot;PhoneNoDbHelper&quot;, &quot;version =&quot; + str2 + &quot;, versionLength = &quot; + i4);
    try {
        ContentValues contentValues = new ContentValues();
        contentValues.put(&quot;ver&quot;, str2);
        sQLiteDatabase.insert(&quot;version&quot;, null, contentValues);
    } catch (Exception e3) {
        Log.e(&quot;PhoneNoDbHelper&quot;, BuildConfig.FLAVOR + e3);
    }
    File fileA2 = b.a(PhoneNoInquireProvider.f301x);
    InputStream inputStreamOpen2 = this.f740d.getResources().getAssets().open(&quot;ExtendNumber.dat&quot;);
    FileOutputStream fileOutputStream2 = new FileOutputStream(fileA2);
    while (true) {
        int i5 = inputStreamOpen2.read(bArr);
        if (i5 == -1) {
            break;
        } else {
            fileOutputStream2.write(bArr, 0, i5);
        }
    }
    inputStreamOpen2.close();
    fileOutputStream2.close();
    f(dataInputStream, sQLiteDatabase);
    File fileA3 = b.a(PhoneNoInquireProvider.f302y);
    InputStream inputStreamOpen3 = this.f740d.getResources().getAssets().open(&quot;city_name_table.txt&quot;);
    FileOutputStream fileOutputStream3 = new FileOutputStream(fileA3);
    while (true) {
        int i6 = inputStreamOpen3.read(bArr);
        if (i6 == -1) {
            break;
        } else {
            fileOutputStream3.write(bArr, 0, i6);
        }
    }
    inputStreamOpen3.close();
    fileOutputStream3.close();
    d(sQLiteDatabase);
    try {
        h(sQLiteDatabase);
    } catch (Exception e4) {
        Log.e(&quot;PhoneNoDbHelper&quot;, &quot;updateCityCode fail &quot; + e4);
    }
    try {
        b.b(new File(PhoneNoInquireProvider.f303z));
        OplusLocaleChangeJobIntentService.n(PhoneNumberAreaApplication.b(&quot;Multi_Language_Table.txt&quot;, PhoneNoInquireProvider.f303z), this.f740d, sQLiteDatabase, str);
    } catch (Exception e5) {
        try {
            OplusLocaleChangeJobIntentService.n(null, this.f740d, sQLiteDatabase, str + &quot;-Exception&quot;);
        } catch (Exception e6) {
            Log.e(&quot;PhoneNoDbHelper&quot;, &quot;e = &quot; + e6);
        }
        Log.e(&quot;PhoneNoDbHelper&quot;, &quot;e = &quot; + e5);
    }
    fileInputStream.close();
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;更关键的是用于解析字典表的 &lt;code&gt;f()&lt;/code&gt; 方法。代码展示了它是如何通过跳过核心数据区，直接读取尾部的城市字典的：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;    private void f(DataInputStream dataInputStream, SQLiteDatabase sQLiteDatabase) throws IOException {
        byte[] bArr = new byte[2];
        byte[] bArr2 = new byte[2000];
        byte[] bArr3 = new byte[8000];
        byte[] bArr4 = new byte[2000];
        dataInputStream.skip(dataInputStream.available() - 12002); // 直接跳到文件末尾的倒数 12002 字节处
        dataInputStream.read(bArr); // 数量标识
        dataInputStream.read(bArr2); // 区号区
        dataInputStream.read(bArr3); // 城市名区
        dataInputStream.read(bArr4); // 扩展标记区
        if (f738e) {
            Log.d(&quot;PhoneNoDbHelper&quot;, &quot;cityNum:&quot; + ((bArr[1] &amp;amp; 255) | (bArr[0] &amp;lt;&amp;lt; 8)));
        }
        Log.d(&quot;PhoneNoDbHelper&quot;, &quot;start insert areano_and_citynames table&quot;);
        for (int i3 = 0; i3 &amp;lt; 400; i3++) {
            try {
                String strTrim = new String(bArr2, i3 * 5, 5).trim();
                String strTrim2 = new String(bArr3, i3 * 20, 20, &quot;gbk&quot;).trim();
                if (strTrim.equals(BuildConfig.FLAVOR) &amp;amp;&amp;amp; strTrim2.equals(BuildConfig.FLAVOR)) {
                    break;
                }
                sQLiteDatabase.execSQL(&quot;insert into areano_and_citynames(areano,cityname) values (&apos;&quot; + strTrim + &quot;&apos;,&apos;&quot; + strTrim2 + &quot;&apos;);&quot;);
            } catch (Exception unused) {
                Log.e(&quot;PhoneNoDbHelper&quot;, &quot;init database failed&quot;);
                return;
            }
        }
        SharedPreferences.Editor editorEdit = this.f740d.getSharedPreferences(&quot;expand&quot;, 0).edit();
        editorEdit.clear();
        for (int i4 = 0; i4 &amp;lt; 1000; i4++) {
            int i5 = i4 * 2;
            int i6 = (bArr4[i5] &amp;amp; 255) &amp;lt;&amp;lt; 8;
            int i7 = bArr4[i5 + 1] &amp;amp; 255;
            if (i6 == 0 &amp;amp;&amp;amp; i7 == 0) {
                break;
            }
            editorEdit.putString(Integer.toString(i4), Integer.toString(i6 + i7));
        }
        editorEdit.commit();
        dataInputStream.close();
        Log.d(&quot;PhoneNoDbHelper&quot;, &quot;init database sucess&quot;);
    }
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;通过上述代码，我们可以清晰地得出尾部字典的结构：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;bArr2&lt;/code&gt;：存放了 400 个区号，每个固定占 5 个字节（需执行 &lt;code&gt;.trim()&lt;/code&gt; 去除空格）。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;bArr3&lt;/code&gt;：存放了 400 个城市名称，每个固定占 20 个字节（需使用 &lt;code&gt;GBK&lt;/code&gt; 解码）。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;bArr4&lt;/code&gt;：1000 个 16 位的扩展号段标记。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;遗憾的是，当试图查看最核心的查询方法 &lt;code&gt;l()&lt;/code&gt; 和初始化号码树的方法 &lt;code&gt;F()&lt;/code&gt; 时，Jadx 提示 &lt;code&gt;Method dump skipped&lt;/code&gt;。由于方法体过长或逻辑过于复杂，反编译引擎放弃了转换。无奈之下，只能硬着头皮去阅读底层的 &lt;strong&gt;Smali 汇编指令&lt;/strong&gt;。&lt;/p&gt;
&lt;h2&gt;4. 还原真正的核心号码映射&lt;/h2&gt;
&lt;h3&gt;4.1 内存字典库初始化 (&lt;code&gt;F()&lt;/code&gt; 方法)&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;.method public F()V
    .registers 20

    move-object/from16 v1, p0

    const-string v2, &quot;expand&quot;

    const-string v3, &quot; bytes&quot;

    const-string v4, &quot;PhoneNumberData_3_1_0.dat&quot;

    const-string v5, &quot;skip fail&quot;

    const-string v6, &quot;Exception when close resfile &quot;

    const-string v7, &quot;PhoneNoProvider&quot;

    .line 1
    iget-object v0, v1, Lcom/oplus/phonenoareainquire/PhoneNoInquireProvider;-&amp;gt;a:Ljava/util/HashMap;

    if-nez v0, :cond_1a

    .line 2
    new-instance v0, Ljava/util/HashMap;

    invoke-direct {v0}, Ljava/util/HashMap;-&amp;gt;&amp;lt;init&amp;gt;()V

    iput-object v0, v1, Lcom/oplus/phonenoareainquire/PhoneNoInquireProvider;-&amp;gt;a:Ljava/util/HashMap;

    goto :goto_1d

    .line 3
    :cond_1a
    invoke-virtual {v0}, Ljava/util/HashMap;-&amp;gt;clear()V

    :goto_1d
    const/4 v8, 0x0

    const/16 v0, 0x82

    move v9, v8

    move v10, v9

    :goto_22
    const/16 v11, 0xa

    if-ge v9, v11, :cond_3a

    .line 4
    iget-object v11, v1, Lcom/oplus/phonenoareainquire/PhoneNoInquireProvider;-&amp;gt;a:Ljava/util/HashMap;

    invoke-static {v0}, Ljava/lang/Integer;-&amp;gt;toString(I)Ljava/lang/String;

    move-result-object v12

    invoke-static {v10}, Ljava/lang/Integer;-&amp;gt;valueOf(I)Ljava/lang/Integer;

    move-result-object v13

    invoke-virtual {v11, v12, v13}, Ljava/util/HashMap;-&amp;gt;put(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;

    add-int/lit16 v10, v10, 0x2710

    add-int/lit8 v9, v9, 0x1

    add-int/lit8 v0, v0, 0x1

    goto :goto_22

    :cond_3a
    const/16 v0, 0x96

    move v9, v8

    :goto_3d
    if-ge v9, v11, :cond_53

    .line 5
    iget-object v12, v1, Lcom/oplus/phonenoareainquire/PhoneNoInquireProvider;-&amp;gt;a:Ljava/util/HashMap;

    invoke-static {v0}, Ljava/lang/Integer;-&amp;gt;toString(I)Ljava/lang/String;

    move-result-object v13

    invoke-static {v10}, Ljava/lang/Integer;-&amp;gt;valueOf(I)Ljava/lang/Integer;

    move-result-object v14

    invoke-virtual {v12, v13, v14}, Ljava/util/HashMap;-&amp;gt;put(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;

    add-int/lit16 v10, v10, 0x2710

    add-int/lit8 v9, v9, 0x1

    add-int/lit8 v0, v0, 0x1

    goto :goto_3d

    .line 6
    :cond_53
    iget-object v0, v1, Lcom/oplus/phonenoareainquire/PhoneNoInquireProvider;-&amp;gt;a:Ljava/util/HashMap;

    const-string v9, &quot;188&quot;

    invoke-static {v10}, Ljava/lang/Integer;-&amp;gt;valueOf(I)Ljava/lang/Integer;

    move-result-object v11

    invoke-virtual {v0, v9, v11}, Ljava/util/HashMap;-&amp;gt;put(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;

    add-int/lit16 v10, v10, 0x2710

    .line 7
    iget-object v0, v1, Lcom/oplus/phonenoareainquire/PhoneNoInquireProvider;-&amp;gt;a:Ljava/util/HashMap;

    const-string v9, &quot;189&quot;

    invoke-static {v10}, Ljava/lang/Integer;-&amp;gt;valueOf(I)Ljava/lang/Integer;

    move-result-object v11

    invoke-virtual {v0, v9, v11}, Ljava/util/HashMap;-&amp;gt;put(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;

    add-int/lit16 v10, v10, 0x2710

    const/4 v9, -0x1

    const v11, 0x19000

    .line 8
    :try_start_71
    new-instance v12, Ljava/io/FileInputStream;

    sget-object v0, Lcom/oplus/phonenoareainquire/PhoneNoInquireProvider;-&amp;gt;w:Ljava/lang/String;

    invoke-direct {v12, v0}, Ljava/io/FileInputStream;-&amp;gt;&amp;lt;init&amp;gt;(Ljava/lang/String;)V
    :try_end_78
    .catch Ljava/io/IOException; {:try_start_71 .. :try_end_78} :catch_20b
    .catch Ljava/lang/Exception; {:try_start_71 .. :try_end_78} :catch_1d4
    .catchall {:try_start_71 .. :try_end_78} :catchall_1cf

    .line 9
    :try_start_78
    invoke-virtual {v12}, Ljava/io/FileInputStream;-&amp;gt;available()I

    move-result v0
    :try_end_7c
    .catch Ljava/io/IOException; {:try_start_78 .. :try_end_7c} :catch_1ca
    .catch Ljava/lang/Exception; {:try_start_78 .. :try_end_7c} :catch_115
    .catchall {:try_start_78 .. :try_end_7c} :catchall_217

    if-nez v0, :cond_11f

    .line 10
    :try_start_7e
    invoke-static {}, Landroid/os/SystemClock;-&amp;gt;elapsedRealtime()J

    move-result-wide v17

    .line 11
    new-instance v0, Ljava/io/File;

    sget-object v13, Lcom/oplus/phonenoareainquire/PhoneNoInquireProvider;-&amp;gt;w:Ljava/lang/String;

    invoke-direct {v0, v13}, Ljava/io/File;-&amp;gt;&amp;lt;init&amp;gt;(Ljava/lang/String;)V

    .line 12
    invoke-virtual {v0}, Ljava/io/File;-&amp;gt;delete()Z

    .line 13
    invoke-virtual {v0}, Ljava/io/File;-&amp;gt;createNewFile()Z

    .line 14
    new-instance v13, Ljava/io/FileOutputStream;

    invoke-direct {v13, v0}, Ljava/io/FileOutputStream;-&amp;gt;&amp;lt;init&amp;gt;(Ljava/io/File;)V
    :try_end_94
    .catch Ljava/io/IOException; {:try_start_7e .. :try_end_94} :catch_119
    .catch Ljava/lang/Exception; {:try_start_7e .. :try_end_94} :catch_115
    .catchall {:try_start_7e .. :try_end_94} :catchall_217

    :try_start_94
    const-string v0, &quot;copy PhoneNumberData.dat to /data/data/ again&quot;

    .line 15
    invoke-static {v7, v0}, Landroid/util/Log;-&amp;gt;d(Ljava/lang/String;Ljava/lang/String;)I

    new-array v0, v11, [B

    .line 16
    invoke-virtual/range {p0 .. p0}, Landroid/content/ContentProvider;-&amp;gt;getContext()Landroid/content/Context;

    move-result-object v16

    invoke-virtual/range {v16 .. v16}, Landroid/content/Context;-&amp;gt;getResources()Landroid/content/res/Resources;

    move-result-object v16

    invoke-virtual/range {v16 .. v16}, Landroid/content/res/Resources;-&amp;gt;getAssets()Landroid/content/res/AssetManager;

    move-result-object v11

    invoke-virtual {v11, v4}, Landroid/content/res/AssetManager;-&amp;gt;open(Ljava/lang/String;)Ljava/io/InputStream;

    move-result-object v11
    :try_end_ab
    .catch Ljava/io/IOException; {:try_start_94 .. :try_end_ab} :catch_111
    .catch Ljava/lang/Exception; {:try_start_94 .. :try_end_ab} :catch_115
    .catchall {:try_start_94 .. :try_end_ab} :catchall_217

    .line 17
    :goto_ab
    :try_start_ab
    invoke-virtual {v11, v0}, Ljava/io/InputStream;-&amp;gt;read([B)I

    move-result v14

    if-eq v14, v9, :cond_b5

    .line 18
    invoke-virtual {v13, v0, v8, v14}, Ljava/io/FileOutputStream;-&amp;gt;write([BII)V

    goto :goto_ab

    .line 19
    :cond_b5
    invoke-virtual {v13}, Ljava/io/OutputStream;-&amp;gt;flush()V

    .line 20
    invoke-virtual {v13}, Ljava/io/FileOutputStream;-&amp;gt;close()V
    :try_end_bb
    .catchall {:try_start_ab .. :try_end_bb} :catchall_103

    .line 21
    :try_start_bb
    invoke-virtual {v12}, Ljava/io/FileInputStream;-&amp;gt;close()V
    :try_end_be
    .catch Ljava/lang/Exception; {:try_start_bb .. :try_end_be} :catch_bf
    .catchall {:try_start_bb .. :try_end_be} :catchall_103

    goto :goto_d5

    :catch_bf
    move-exception v0

    move-object v14, v0

    .line 22
    :try_start_c1
    new-instance v0, Ljava/lang/StringBuilder;

    invoke-direct {v0}, Ljava/lang/StringBuilder;-&amp;gt;&amp;lt;init&amp;gt;()V

    const-string v15, &quot;exception when close resFile &quot;

    invoke-virtual {v0, v15}, Ljava/lang/StringBuilder;-&amp;gt;append(Ljava/lang/String;)Ljava/lang/StringBuilder;

    invoke-virtual {v0, v14}, Ljava/lang/StringBuilder;-&amp;gt;append(Ljava/lang/Object;)Ljava/lang/StringBuilder;

    invoke-virtual {v0}, Ljava/lang/StringBuilder;-&amp;gt;toString()Ljava/lang/String;

    move-result-object v0

    invoke-static {v7, v0}, Landroid/util/Log;-&amp;gt;e(Ljava/lang/String;Ljava/lang/String;)I
    :try_end_d5
    .catchall {:try_start_c1 .. :try_end_d5} :catchall_103

    .line 23
    :goto_d5
    :try_start_d5
    invoke-virtual {v11}, Ljava/io/InputStream;-&amp;gt;close()V

    .line 24
    new-instance v14, Ljava/io/FileInputStream;

    sget-object v0, Lcom/oplus/phonenoareainquire/PhoneNoInquireProvider;-&amp;gt;w:Ljava/lang/String;

    invoke-direct {v14, v0}, Ljava/io/FileInputStream;-&amp;gt;&amp;lt;init&amp;gt;(Ljava/lang/String;)V
    :try_end_df
    .catch Ljava/io/IOException; {:try_start_d5 .. :try_end_df} :catch_111
    .catch Ljava/lang/Exception; {:try_start_d5 .. :try_end_df} :catch_115
    .catchall {:try_start_d5 .. :try_end_df} :catchall_217

    .line 25
    :try_start_df
    new-instance v0, Ljava/lang/StringBuilder;

    invoke-direct {v0}, Ljava/lang/StringBuilder;-&amp;gt;&amp;lt;init&amp;gt;()V

    const-string v11, &quot;copySourceFile time = &quot;

    invoke-virtual {v0, v11}, Ljava/lang/StringBuilder;-&amp;gt;append(Ljava/lang/String;)Ljava/lang/StringBuilder;

    invoke-static {}, Landroid/os/SystemClock;-&amp;gt;elapsedRealtime()J

    move-result-wide v11

    sub-long v11, v11, v17

    invoke-virtual {v0, v11, v12}, Ljava/lang/StringBuilder;-&amp;gt;append(J)Ljava/lang/StringBuilder;

    invoke-virtual {v0}, Ljava/lang/StringBuilder;-&amp;gt;toString()Ljava/lang/String;

    move-result-object v0

    invoke-static {v7, v0}, Landroid/util/Log;-&amp;gt;d(Ljava/lang/String;Ljava/lang/String;)I
    :try_end_f9
    .catch Ljava/io/IOException; {:try_start_df .. :try_end_f9} :catch_fc
    .catch Ljava/lang/Exception; {:try_start_df .. :try_end_f9} :catch_1c0
    .catchall {:try_start_df .. :try_end_f9} :catchall_207

    move-object/from16 v16, v13

    goto :goto_122

    :catch_fc
    move-exception v0

    move-object v9, v1

    move-object v12, v14

    move-object v1, v0

    move-object v14, v13

    goto/16 :goto_211

    :catchall_103
    move-exception v0

    move-object v14, v0

    if-eqz v11, :cond_110

    .line 26
    :try_start_107
    invoke-virtual {v11}, Ljava/io/InputStream;-&amp;gt;close()V
    :try_end_10a
    .catchall {:try_start_107 .. :try_end_10a} :catchall_10b

    goto :goto_110

    :catchall_10b
    move-exception v0

    move-object v11, v0

    :try_start_10d
    invoke-virtual {v14, v11}, Ljava/lang/Throwable;-&amp;gt;addSuppressed(Ljava/lang/Throwable;)V

    :cond_110
    :goto_110
    throw v14
    :try_end_111
    .catch Ljava/io/IOException; {:try_start_10d .. :try_end_111} :catch_111
    .catch Ljava/lang/Exception; {:try_start_10d .. :try_end_111} :catch_115
    .catchall {:try_start_10d .. :try_end_111} :catchall_217

    :catch_111
    move-exception v0

    move-object v9, v1

    move-object v14, v13

    goto :goto_11c

    :catch_115
    move-exception v0

    move-object v14, v12

    goto/16 :goto_1d6

    :catch_119
    move-exception v0

    move-object v9, v1

    const/4 v14, 0x0

    :goto_11c
    move-object v1, v0

    goto/16 :goto_211

    :cond_11f
    move-object v14, v12

    const/16 v16, 0x0

    .line 27
    :goto_122
    :try_start_122
    new-instance v0, Ljava/io/DataInputStream;

    invoke-direct {v1, v14}, Lcom/oplus/phonenoareainquire/PhoneNoInquireProvider;-&amp;gt;d(Ljava/io/InputStream;)Ljava/io/InputStream;

    move-result-object v11

    invoke-direct {v0, v11}, Ljava/io/DataInputStream;-&amp;gt;&amp;lt;init&amp;gt;(Ljava/io/InputStream;)V

    invoke-virtual {v1, v0}, Lcom/oplus/phonenoareainquire/PhoneNoInquireProvider;-&amp;gt;K(Ljava/io/DataInputStream;)V

    .line 28
    invoke-virtual {v14}, Ljava/io/FileInputStream;-&amp;gt;getChannel()Ljava/nio/channels/FileChannel;

    move-result-object v0

    const-wide/16 v11, 0x0

    invoke-virtual {v0, v11, v12}, Ljava/nio/channels/FileChannel;-&amp;gt;position(J)Ljava/nio/channels/FileChannel;
    :try_end_137
    .catch Ljava/io/IOException; {:try_start_122 .. :try_end_137} :catch_1c2
    .catch Ljava/lang/Exception; {:try_start_122 .. :try_end_137} :catch_1c0
    .catchall {:try_start_122 .. :try_end_137} :catchall_207

    move v13, v10

    const-wide/16 v9, 0x10

    .line 29
    :try_start_13a
    invoke-virtual {v14, v9, v10}, Ljava/io/FileInputStream;-&amp;gt;skip(J)J

    move-result-wide v0

    cmp-long v9, v0, v11

    if-lez v9, :cond_15a

    .line 30
    new-instance v9, Ljava/lang/StringBuilder;

    invoke-direct {v9}, Ljava/lang/StringBuilder;-&amp;gt;&amp;lt;init&amp;gt;()V

    const-string v10, &quot;skip &quot;

    invoke-virtual {v9, v10}, Ljava/lang/StringBuilder;-&amp;gt;append(Ljava/lang/String;)Ljava/lang/StringBuilder;

    invoke-virtual {v9, v0, v1}, Ljava/lang/StringBuilder;-&amp;gt;append(J)Ljava/lang/StringBuilder;

    invoke-virtual {v9, v3}, Ljava/lang/StringBuilder;-&amp;gt;append(Ljava/lang/String;)Ljava/lang/StringBuilder;

    invoke-virtual {v9}, Ljava/lang/StringBuilder;-&amp;gt;toString()Ljava/lang/String;

    move-result-object v0

    invoke-static {v7, v0}, Landroid/util/Log;-&amp;gt;d(Ljava/lang/String;Ljava/lang/String;)I

    goto :goto_15d

    .line 31
    :cond_15a
    invoke-static {v7, v5}, Landroid/util/Log;-&amp;gt;d(Ljava/lang/String;Ljava/lang/String;)I

    .line 32
    :goto_15d
    invoke-virtual {v14}, Ljava/io/FileInputStream;-&amp;gt;available()I

    move-result v0

    .line 33
    invoke-virtual {v14}, Ljava/io/FileInputStream;-&amp;gt;available()I

    move-result v1

    new-array v1, v1, [B
    :try_end_167
    .catch Ljava/io/IOException; {:try_start_13a .. :try_end_167} :catch_1ba
    .catch Ljava/lang/Exception; {:try_start_13a .. :try_end_167} :catch_1c0
    .catchall {:try_start_13a .. :try_end_167} :catchall_207

    move-object/from16 v9, p0

    :try_start_169
    iput-object v1, v9, Lcom/oplus/phonenoareainquire/PhoneNoInquireProvider;-&amp;gt;b:[B

    move v1, v8

    :goto_16c
    if-ge v1, v0, :cond_178

    .line 34
    iget-object v10, v9, Lcom/oplus/phonenoareainquire/PhoneNoInquireProvider;-&amp;gt;b:[B

    sub-int v11, v0, v1

    invoke-virtual {v14, v10, v1, v11}, Ljava/io/FileInputStream;-&amp;gt;read([BII)I

    move-result v10

    add-int/2addr v1, v10

    goto :goto_16c

    .line 35
    :cond_178
    invoke-virtual {v14}, Ljava/io/FileInputStream;-&amp;gt;close()V

    .line 36
    invoke-virtual/range {p0 .. p0}, Landroid/content/ContentProvider;-&amp;gt;getContext()Landroid/content/Context;

    move-result-object v0

    invoke-virtual {v0, v2, v8}, Landroid/content/Context;-&amp;gt;getSharedPreferences(Ljava/lang/String;I)Landroid/content/SharedPreferences;

    move-result-object v0

    .line 37
    invoke-interface {v0}, Landroid/content/SharedPreferences;-&amp;gt;getAll()Ljava/util/Map;

    move-result-object v0

    check-cast v0, Ljava/util/HashMap;
    :try_end_189
    .catch Ljava/io/IOException; {:try_start_169 .. :try_end_189} :catch_1b8
    .catch Ljava/lang/Exception; {:try_start_169 .. :try_end_189} :catch_1c0
    .catchall {:try_start_169 .. :try_end_189} :catchall_207

    move v1, v8

    move v10, v13

    .line 38
    :goto_18b
    :try_start_18b
    invoke-virtual {v0}, Ljava/util/HashMap;-&amp;gt;size()I

    move-result v11

    if-ge v1, v11, :cond_1a9

    .line 39
    invoke-static {v1}, Ljava/lang/Integer;-&amp;gt;toString(I)Ljava/lang/String;

    move-result-object v11

    invoke-virtual {v0, v11}, Ljava/util/HashMap;-&amp;gt;get(Ljava/lang/Object;)Ljava/lang/Object;

    move-result-object v11

    check-cast v11, Ljava/lang/String;

    .line 40
    iget-object v12, v9, Lcom/oplus/phonenoareainquire/PhoneNoInquireProvider;-&amp;gt;a:Ljava/util/HashMap;

    invoke-static {v10}, Ljava/lang/Integer;-&amp;gt;valueOf(I)Ljava/lang/Integer;

    move-result-object v13

    invoke-virtual {v12, v11, v13}, Ljava/util/HashMap;-&amp;gt;put(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
    :try_end_1a4
    .catch Ljava/io/IOException; {:try_start_18b .. :try_end_1a4} :catch_1b6
    .catch Ljava/lang/Exception; {:try_start_18b .. :try_end_1a4} :catch_1c0
    .catchall {:try_start_18b .. :try_end_1a4} :catchall_207

    add-int/lit16 v10, v10, 0x2710

    add-int/lit8 v1, v1, 0x1

    goto :goto_18b

    .line 41
    :cond_1a9
    :try_start_1a9
    invoke-virtual {v14}, Ljava/io/FileInputStream;-&amp;gt;close()V
    :try_end_1ac
    .catch Ljava/lang/Exception; {:try_start_1a9 .. :try_end_1ac} :catch_1ae

    goto/16 :goto_393

    :catch_1ae
    move-exception v0

    move-object v1, v0

    .line 42
    new-instance v0, Ljava/lang/StringBuilder;

    invoke-direct {v0}, Ljava/lang/StringBuilder;-&amp;gt;&amp;lt;init&amp;gt;()V

    goto :goto_1f8

    :catch_1b6
    move-exception v0

    goto :goto_1c5

    :catch_1b8
    move-exception v0

    goto :goto_1bd

    :catch_1ba
    move-exception v0

    move-object/from16 v9, p0

    :goto_1bd
    move-object v1, v0

    move v10, v13

    goto :goto_1c6

    :catch_1c0
    move-exception v0

    goto :goto_1d6

    :catch_1c2
    move-exception v0

    move-object v9, v1

    move v13, v10

    :goto_1c5
    move-object v1, v0

    :goto_1c6
    move-object v12, v14

    move-object/from16 v14, v16

    goto :goto_211

    :catch_1ca
    move-exception v0

    move-object v9, v1

    move v13, v10

    move-object v1, v0

    goto :goto_210

    :catchall_1cf
    move-exception v0

    move-object v1, v0

    const/4 v14, 0x0

    goto/16 :goto_3af

    :catch_1d4
    move-exception v0

    const/4 v14, 0x0

    .line 43
    :goto_1d6
    :try_start_1d6
    new-instance v1, Ljava/lang/StringBuilder;

    invoke-direct {v1}, Ljava/lang/StringBuilder;-&amp;gt;&amp;lt;init&amp;gt;()V

    const-string v2, &quot;Exception when load number data to cache &quot;

    invoke-virtual {v1, v2}, Ljava/lang/StringBuilder;-&amp;gt;append(Ljava/lang/String;)Ljava/lang/StringBuilder;

    invoke-virtual {v1, v0}, Ljava/lang/StringBuilder;-&amp;gt;append(Ljava/lang/Object;)Ljava/lang/StringBuilder;

    invoke-virtual {v1}, Ljava/lang/StringBuilder;-&amp;gt;toString()Ljava/lang/String;

    move-result-object v0

    invoke-static {v7, v0}, Landroid/util/Log;-&amp;gt;e(Ljava/lang/String;Ljava/lang/String;)I
    :try_end_1ea
    .catchall {:try_start_1d6 .. :try_end_1ea} :catchall_207

    if-eqz v14, :cond_393

    .line 44
    :try_start_1ec
    invoke-virtual {v14}, Ljava/io/FileInputStream;-&amp;gt;close()V
    :try_end_1ef
    .catch Ljava/lang/Exception; {:try_start_1ec .. :try_end_1ef} :catch_1f1

    goto/16 :goto_393

    :catch_1f1
    move-exception v0

    move-object v1, v0

    .line 45
    new-instance v0, Ljava/lang/StringBuilder;

    invoke-direct {v0}, Ljava/lang/StringBuilder;-&amp;gt;&amp;lt;init&amp;gt;()V

    :goto_1f8
    invoke-virtual {v0, v6}, Ljava/lang/StringBuilder;-&amp;gt;append(Ljava/lang/String;)Ljava/lang/StringBuilder;

    invoke-virtual {v0, v1}, Ljava/lang/StringBuilder;-&amp;gt;append(Ljava/lang/Object;)Ljava/lang/StringBuilder;

    invoke-virtual {v0}, Ljava/lang/StringBuilder;-&amp;gt;toString()Ljava/lang/String;

    move-result-object v0

    invoke-static {v7, v0}, Landroid/util/Log;-&amp;gt;e(Ljava/lang/String;Ljava/lang/String;)I

    goto/16 :goto_393

    :catchall_207
    move-exception v0

    move-object v1, v0

    goto/16 :goto_3af

    :catch_20b
    move-exception v0

    move-object v9, v1

    move v13, v10

    move-object v1, v0

    const/4 v12, 0x0

    :goto_210
    const/4 v14, 0x0

    :goto_211
    if-eqz v14, :cond_232

    .line 46
    :try_start_213
    invoke-virtual {v14}, Ljava/io/FileOutputStream;-&amp;gt;close()V
    :try_end_216
    .catch Ljava/lang/Exception; {:try_start_213 .. :try_end_216} :catch_21c
    .catchall {:try_start_213 .. :try_end_216} :catchall_217

    goto :goto_232

    :catchall_217
    move-exception v0

    move-object v1, v0

    move-object v14, v12

    goto/16 :goto_3af

    :catch_21c
    move-exception v0

    move-object v11, v0

    .line 47
    :try_start_21e
    new-instance v0, Ljava/lang/StringBuilder;

    invoke-direct {v0}, Ljava/lang/StringBuilder;-&amp;gt;&amp;lt;init&amp;gt;()V

    const-string v13, &quot;Exception when close tarFile in Exception &quot;

    invoke-virtual {v0, v13}, Ljava/lang/StringBuilder;-&amp;gt;append(Ljava/lang/String;)Ljava/lang/StringBuilder;

    invoke-virtual {v0, v11}, Ljava/lang/StringBuilder;-&amp;gt;append(Ljava/lang/Object;)Ljava/lang/StringBuilder;

    invoke-virtual {v0}, Ljava/lang/StringBuilder;-&amp;gt;toString()Ljava/lang/String;

    move-result-object v0

    invoke-static {v7, v0}, Landroid/util/Log;-&amp;gt;e(Ljava/lang/String;Ljava/lang/String;)I
    :try_end_232
    .catchall {:try_start_21e .. :try_end_232} :catchall_217

    :cond_232
    :goto_232
    const-string v11, &quot;Exception when close tarFile &quot;

    if-eqz v12, :cond_254

    .line 48
    :try_start_236
    invoke-virtual {v12}, Ljava/io/FileInputStream;-&amp;gt;close()V
    :try_end_239
    .catch Ljava/lang/Exception; {:try_start_236 .. :try_end_239} :catch_23e
    .catchall {:try_start_236 .. :try_end_239} :catchall_23a

    goto :goto_254

    :catchall_23a
    move-exception v0

    move-object v1, v0

    goto/16 :goto_394

    :catch_23e
    move-exception v0

    move-object v13, v0

    .line 49
    :try_start_240
    new-instance v0, Ljava/lang/StringBuilder;

    invoke-direct {v0}, Ljava/lang/StringBuilder;-&amp;gt;&amp;lt;init&amp;gt;()V

    const-string v15, &quot;Exception when close resFile &quot;

    invoke-virtual {v0, v15}, Ljava/lang/StringBuilder;-&amp;gt;append(Ljava/lang/String;)Ljava/lang/StringBuilder;

    invoke-virtual {v0, v13}, Ljava/lang/StringBuilder;-&amp;gt;append(Ljava/lang/Object;)Ljava/lang/StringBuilder;

    invoke-virtual {v0}, Ljava/lang/StringBuilder;-&amp;gt;toString()Ljava/lang/String;

    move-result-object v0

    invoke-static {v7, v0}, Landroid/util/Log;-&amp;gt;e(Ljava/lang/String;Ljava/lang/String;)I

    :cond_254
    :goto_254
    const-string v0, &quot;IOException copySourceFile  again&quot;

    .line 50
    invoke-static {v7, v0}, Landroid/util/Log;-&amp;gt;d(Ljava/lang/String;Ljava/lang/String;)I

    .line 51
    new-instance v0, Ljava/io/File;

    sget-object v13, Lcom/oplus/phonenoareainquire/PhoneNoInquireProvider;-&amp;gt;w:Ljava/lang/String;

    invoke-direct {v0, v13}, Ljava/io/File;-&amp;gt;&amp;lt;init&amp;gt;(Ljava/lang/String;)V

    .line 52
    invoke-virtual {v0}, Ljava/io/File;-&amp;gt;delete()Z

    .line 53
    invoke-virtual {v0}, Ljava/io/File;-&amp;gt;createNewFile()Z

    const-string v13, &quot;IOException copy PhoneNumberData.dat to /data/data/ again&quot;

    .line 54
    invoke-static {v7, v13}, Landroid/util/Log;-&amp;gt;d(Ljava/lang/String;Ljava/lang/String;)I

    .line 55
    new-instance v13, Ljava/io/FileOutputStream;

    invoke-direct {v13, v0}, Ljava/io/FileOutputStream;-&amp;gt;&amp;lt;init&amp;gt;(Ljava/io/File;)V
    :try_end_270
    .catch Ljava/lang/Exception; {:try_start_240 .. :try_end_270} :catch_340
    .catchall {:try_start_240 .. :try_end_270} :catchall_23a

    const v14, 0x19000

    :try_start_273
    new-array v0, v14, [B

    .line 56
    invoke-virtual/range {p0 .. p0}, Landroid/content/ContentProvider;-&amp;gt;getContext()Landroid/content/Context;

    move-result-object v14

    invoke-virtual {v14}, Landroid/content/Context;-&amp;gt;getResources()Landroid/content/res/Resources;

    move-result-object v14

    invoke-virtual {v14}, Landroid/content/res/Resources;-&amp;gt;getAssets()Landroid/content/res/AssetManager;

    move-result-object v14

    invoke-virtual {v14, v4}, Landroid/content/res/AssetManager;-&amp;gt;open(Ljava/lang/String;)Ljava/io/InputStream;

    move-result-object v4

    .line 57
    :goto_285
    invoke-virtual {v4, v0}, Ljava/io/InputStream;-&amp;gt;read([B)I

    move-result v14

    const/4 v15, -0x1

    if-eq v14, v15, :cond_290

    .line 58
    invoke-virtual {v13, v0, v8, v14}, Ljava/io/FileOutputStream;-&amp;gt;write([BII)V

    goto :goto_285

    .line 59
    :cond_290
    invoke-virtual {v13}, Ljava/io/OutputStream;-&amp;gt;flush()V

    .line 60
    invoke-virtual {v13}, Ljava/io/FileOutputStream;-&amp;gt;close()V

    .line 61
    new-instance v14, Ljava/io/FileInputStream;

    sget-object v0, Lcom/oplus/phonenoareainquire/PhoneNoInquireProvider;-&amp;gt;w:Ljava/lang/String;

    invoke-direct {v14, v0}, Ljava/io/FileInputStream;-&amp;gt;&amp;lt;init&amp;gt;(Ljava/lang/String;)V
    :try_end_29d
    .catch Ljava/lang/Exception; {:try_start_273 .. :try_end_29d} :catch_33d
    .catchall {:try_start_273 .. :try_end_29d} :catchall_339

    .line 62
    :try_start_29d
    invoke-virtual {v14}, Ljava/io/FileInputStream;-&amp;gt;getChannel()Ljava/nio/channels/FileChannel;

    move-result-object v0

    const-wide/16 v8, 0x0

    invoke-virtual {v0, v8, v9}, Ljava/nio/channels/FileChannel;-&amp;gt;position(J)Ljava/nio/channels/FileChannel;

    move-object v15, v5

    const-wide/16 v4, 0x10

    .line 63
    invoke-virtual {v14, v4, v5}, Ljava/io/FileInputStream;-&amp;gt;skip(J)J

    move-result-wide v4

    cmp-long v0, v4, v8

    if-lez v0, :cond_2c9

    .line 64
    new-instance v0, Ljava/lang/StringBuilder;

    invoke-direct {v0}, Ljava/lang/StringBuilder;-&amp;gt;&amp;lt;init&amp;gt;()V

    const-string v8, &quot; has skiped &quot;

    invoke-virtual {v0, v8}, Ljava/lang/StringBuilder;-&amp;gt;append(Ljava/lang/String;)Ljava/lang/StringBuilder;

    invoke-virtual {v0, v4, v5}, Ljava/lang/StringBuilder;-&amp;gt;append(J)Ljava/lang/StringBuilder;

    invoke-virtual {v0, v3}, Ljava/lang/StringBuilder;-&amp;gt;append(Ljava/lang/String;)Ljava/lang/StringBuilder;

    invoke-virtual {v0}, Ljava/lang/StringBuilder;-&amp;gt;toString()Ljava/lang/String;

    move-result-object v0

    invoke-static {v7, v0}, Landroid/util/Log;-&amp;gt;d(Ljava/lang/String;Ljava/lang/String;)I

    goto :goto_2cd

    :cond_2c9
    move-object v3, v15

    .line 65
    invoke-static {v7, v3}, Landroid/util/Log;-&amp;gt;d(Ljava/lang/String;Ljava/lang/String;)I

    .line 66
    :goto_2cd
    invoke-virtual {v14}, Ljava/io/FileInputStream;-&amp;gt;available()I

    move-result v0

    .line 67
    invoke-virtual {v14}, Ljava/io/FileInputStream;-&amp;gt;available()I

    move-result v3

    new-array v3, v3, [B

    move-object/from16 v4, p0

    iput-object v3, v4, Lcom/oplus/phonenoareainquire/PhoneNoInquireProvider;-&amp;gt;b:[B

    const/4 v3, 0x0

    :goto_2dc
    if-ge v3, v0, :cond_2e8

    .line 68
    iget-object v5, v4, Lcom/oplus/phonenoareainquire/PhoneNoInquireProvider;-&amp;gt;b:[B

    sub-int v8, v0, v3

    invoke-virtual {v14, v5, v3, v8}, Ljava/io/FileInputStream;-&amp;gt;read([BII)I

    move-result v5

    add-int/2addr v3, v5

    goto :goto_2dc

    .line 69
    :cond_2e8
    invoke-virtual {v14}, Ljava/io/FileInputStream;-&amp;gt;close()V

    .line 70
    invoke-virtual/range {p0 .. p0}, Landroid/content/ContentProvider;-&amp;gt;getContext()Landroid/content/Context;

    move-result-object v0

    const/4 v3, 0x0

    invoke-virtual {v0, v2, v3}, Landroid/content/Context;-&amp;gt;getSharedPreferences(Ljava/lang/String;I)Landroid/content/SharedPreferences;

    move-result-object v0

    .line 71
    invoke-interface {v0}, Landroid/content/SharedPreferences;-&amp;gt;getAll()Ljava/util/Map;

    move-result-object v0

    check-cast v0, Ljava/util/HashMap;

    move v8, v3

    .line 72
    :goto_2fb
    invoke-virtual {v0}, Ljava/util/HashMap;-&amp;gt;size()I

    move-result v2

    if-ge v8, v2, :cond_319

    .line 73
    invoke-static {v8}, Ljava/lang/Integer;-&amp;gt;toString(I)Ljava/lang/String;

    move-result-object v2

    invoke-virtual {v0, v2}, Ljava/util/HashMap;-&amp;gt;get(Ljava/lang/Object;)Ljava/lang/Object;

    move-result-object v2

    check-cast v2, Ljava/lang/String;

    .line 74
    iget-object v3, v4, Lcom/oplus/phonenoareainquire/PhoneNoInquireProvider;-&amp;gt;a:Ljava/util/HashMap;

    invoke-static {v10}, Ljava/lang/Integer;-&amp;gt;valueOf(I)Ljava/lang/Integer;

    move-result-object v5

    invoke-virtual {v3, v2, v5}, Ljava/util/HashMap;-&amp;gt;put(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
    :try_end_314
    .catch Ljava/lang/Exception; {:try_start_29d .. :try_end_314} :catch_336
    .catchall {:try_start_29d .. :try_end_314} :catchall_332

    add-int/lit16 v10, v10, 0x2710

    add-int/lit8 v8, v8, 0x1

    goto :goto_2fb

    .line 75
    :cond_319
    :try_start_319
    invoke-virtual {v13}, Ljava/io/FileOutputStream;-&amp;gt;close()V
    :try_end_31c
    .catch Ljava/lang/Exception; {:try_start_319 .. :try_end_31c} :catch_31d
    .catchall {:try_start_319 .. :try_end_31c} :catchall_207

    goto :goto_370

    :catch_31d
    move-exception v0

    move-object v2, v0

    .line 76
    :try_start_31f
    new-instance v0, Ljava/lang/StringBuilder;

    invoke-direct {v0}, Ljava/lang/StringBuilder;-&amp;gt;&amp;lt;init&amp;gt;()V

    invoke-virtual {v0, v11}, Ljava/lang/StringBuilder;-&amp;gt;append(Ljava/lang/String;)Ljava/lang/StringBuilder;

    invoke-virtual {v0, v2}, Ljava/lang/StringBuilder;-&amp;gt;append(Ljava/lang/Object;)Ljava/lang/StringBuilder;

    invoke-virtual {v0}, Ljava/lang/StringBuilder;-&amp;gt;toString()Ljava/lang/String;

    move-result-object v0

    invoke-static {v7, v0}, Landroid/util/Log;-&amp;gt;e(Ljava/lang/String;Ljava/lang/String;)I
    :try_end_331
    .catchall {:try_start_31f .. :try_end_331} :catchall_207

    goto :goto_370

    :catchall_332
    move-exception v0

    move-object v1, v0

    move-object v12, v14

    goto :goto_33b

    :catch_336
    move-exception v0

    move-object v12, v14

    goto :goto_33e

    :catchall_339
    move-exception v0

    move-object v1, v0

    :goto_33b
    move-object v14, v13

    goto :goto_394

    :catch_33d
    move-exception v0

    :goto_33e
    move-object v14, v13

    goto :goto_341

    :catch_340
    move-exception v0

    .line 77
    :goto_341
    :try_start_341
    new-instance v2, Ljava/lang/StringBuilder;

    invoke-direct {v2}, Ljava/lang/StringBuilder;-&amp;gt;&amp;lt;init&amp;gt;()V

    const-string v3, &quot;Exception again:&quot;

    invoke-virtual {v2, v3}, Ljava/lang/StringBuilder;-&amp;gt;append(Ljava/lang/String;)Ljava/lang/StringBuilder;

    invoke-virtual {v2, v0}, Ljava/lang/StringBuilder;-&amp;gt;append(Ljava/lang/Object;)Ljava/lang/StringBuilder;

    invoke-virtual {v2}, Ljava/lang/StringBuilder;-&amp;gt;toString()Ljava/lang/String;

    move-result-object v0

    invoke-static {v7, v0}, Landroid/util/Log;-&amp;gt;e(Ljava/lang/String;Ljava/lang/String;)I
    :try_end_355
    .catchall {:try_start_341 .. :try_end_355} :catchall_23a

    if-eqz v14, :cond_36f

    .line 78
    :try_start_357
    invoke-virtual {v14}, Ljava/io/FileOutputStream;-&amp;gt;close()V
    :try_end_35a
    .catch Ljava/lang/Exception; {:try_start_357 .. :try_end_35a} :catch_35b
    .catchall {:try_start_357 .. :try_end_35a} :catchall_217

    goto :goto_36f

    :catch_35b
    move-exception v0

    move-object v2, v0

    .line 79
    :try_start_35d
    new-instance v0, Ljava/lang/StringBuilder;

    invoke-direct {v0}, Ljava/lang/StringBuilder;-&amp;gt;&amp;lt;init&amp;gt;()V

    invoke-virtual {v0, v11}, Ljava/lang/StringBuilder;-&amp;gt;append(Ljava/lang/String;)Ljava/lang/StringBuilder;

    invoke-virtual {v0, v2}, Ljava/lang/StringBuilder;-&amp;gt;append(Ljava/lang/Object;)Ljava/lang/StringBuilder;

    invoke-virtual {v0}, Ljava/lang/StringBuilder;-&amp;gt;toString()Ljava/lang/String;

    move-result-object v0

    invoke-static {v7, v0}, Landroid/util/Log;-&amp;gt;e(Ljava/lang/String;Ljava/lang/String;)I
    :try_end_36f
    .catchall {:try_start_35d .. :try_end_36f} :catchall_217

    :cond_36f
    :goto_36f
    move-object v14, v12

    .line 80
    :goto_370
    :try_start_370
    new-instance v0, Ljava/lang/StringBuilder;

    invoke-direct {v0}, Ljava/lang/StringBuilder;-&amp;gt;&amp;lt;init&amp;gt;()V

    const-string v2, &quot;IOException: &quot;

    invoke-virtual {v0, v2}, Ljava/lang/StringBuilder;-&amp;gt;append(Ljava/lang/String;)Ljava/lang/StringBuilder;

    invoke-virtual {v0, v1}, Ljava/lang/StringBuilder;-&amp;gt;append(Ljava/lang/Object;)Ljava/lang/StringBuilder;

    invoke-virtual {v0}, Ljava/lang/StringBuilder;-&amp;gt;toString()Ljava/lang/String;

    move-result-object v0

    invoke-static {v7, v0}, Landroid/util/Log;-&amp;gt;e(Ljava/lang/String;Ljava/lang/String;)I
    :try_end_384
    .catchall {:try_start_370 .. :try_end_384} :catchall_207

    if-eqz v14, :cond_393

    .line 81
    :try_start_386
    invoke-virtual {v14}, Ljava/io/FileInputStream;-&amp;gt;close()V
    :try_end_389
    .catch Ljava/lang/Exception; {:try_start_386 .. :try_end_389} :catch_38a

    goto :goto_393

    :catch_38a
    move-exception v0

    move-object v1, v0

    .line 82
    new-instance v0, Ljava/lang/StringBuilder;

    invoke-direct {v0}, Ljava/lang/StringBuilder;-&amp;gt;&amp;lt;init&amp;gt;()V

    goto/16 :goto_1f8

    :cond_393
    :goto_393
    return-void

    :goto_394
    if-eqz v14, :cond_3ae

    .line 83
    :try_start_396
    invoke-virtual {v14}, Ljava/io/FileOutputStream;-&amp;gt;close()V
    :try_end_399
    .catch Ljava/lang/Exception; {:try_start_396 .. :try_end_399} :catch_39a
    .catchall {:try_start_396 .. :try_end_399} :catchall_217

    goto :goto_3ae

    :catch_39a
    move-exception v0

    move-object v2, v0

    .line 84
    :try_start_39c
    new-instance v0, Ljava/lang/StringBuilder;

    invoke-direct {v0}, Ljava/lang/StringBuilder;-&amp;gt;&amp;lt;init&amp;gt;()V

    invoke-virtual {v0, v11}, Ljava/lang/StringBuilder;-&amp;gt;append(Ljava/lang/String;)Ljava/lang/StringBuilder;

    invoke-virtual {v0, v2}, Ljava/lang/StringBuilder;-&amp;gt;append(Ljava/lang/Object;)Ljava/lang/StringBuilder;

    invoke-virtual {v0}, Ljava/lang/StringBuilder;-&amp;gt;toString()Ljava/lang/String;

    move-result-object v0

    invoke-static {v7, v0}, Landroid/util/Log;-&amp;gt;e(Ljava/lang/String;Ljava/lang/String;)I

    .line 85
    :cond_3ae
    :goto_3ae
    throw v1
    :try_end_3af
    .catchall {:try_start_39c .. :try_end_3af} :catchall_217

    :goto_3af
    if-eqz v14, :cond_3c9

    .line 86
    :try_start_3b1
    invoke-virtual {v14}, Ljava/io/FileInputStream;-&amp;gt;close()V
    :try_end_3b4
    .catch Ljava/lang/Exception; {:try_start_3b1 .. :try_end_3b4} :catch_3b5

    goto :goto_3c9

    :catch_3b5
    move-exception v0

    move-object v2, v0

    .line 87
    new-instance v0, Ljava/lang/StringBuilder;

    invoke-direct {v0}, Ljava/lang/StringBuilder;-&amp;gt;&amp;lt;init&amp;gt;()V

    invoke-virtual {v0, v6}, Ljava/lang/StringBuilder;-&amp;gt;append(Ljava/lang/String;)Ljava/lang/StringBuilder;

    invoke-virtual {v0, v2}, Ljava/lang/StringBuilder;-&amp;gt;append(Ljava/lang/Object;)Ljava/lang/StringBuilder;

    invoke-virtual {v0}, Ljava/lang/StringBuilder;-&amp;gt;toString()Ljava/lang/String;

    move-result-object v0

    invoke-static {v7, v0}, Landroid/util/Log;-&amp;gt;e(Ljava/lang/String;Ljava/lang/String;)I

    .line 88
    :cond_3c9
    :goto_3c9
    throw v1
.end method
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;阅读 Smali 代码后发现，在 &lt;code&gt;F()&lt;/code&gt; 方法中，系统构建了一个名为 &lt;code&gt;this.a&lt;/code&gt; 的 &lt;code&gt;HashMap&lt;/code&gt;。这个 Map 存放的是手机号&lt;strong&gt;前三位（基础号段）对应的内存基础偏移量&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;代码通过循环，为 &lt;code&gt;130-139&lt;/code&gt;、&lt;code&gt;150-159&lt;/code&gt; 以及 &lt;code&gt;188&lt;/code&gt;、&lt;code&gt;189&lt;/code&gt; 等基础号段分配了递增的偏移值。例如：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;130&lt;/code&gt; 对应偏移量 &lt;code&gt;0&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;131&lt;/code&gt; 对应偏移量 &lt;code&gt;10000&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;132&lt;/code&gt; 对应偏移量 &lt;code&gt;20000&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;随后，它还会从尾部的扩展区中读取诸如 &lt;code&gt;170&lt;/code&gt;、&lt;code&gt;199&lt;/code&gt; 等较新的号段，并将它们同样补充进该 HashMap 中。&lt;/p&gt;
&lt;h3&gt;4.2 号段的数学映射模型 (&lt;code&gt;l()&lt;/code&gt; 方法)&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;.method public l(Ljava/lang/String;)Landroid/database/Cursor;
    .registers 15

    const-string v0, &quot;10&quot;

    .line 1
    invoke-static {p1}, Landroid/text/TextUtils;-&amp;gt;isEmpty(Ljava/lang/CharSequence;)Z

    move-result v1

    const-string v2, &quot;PhoneNoProvider&quot;

    const/4 v3, 0x0

    if-eqz v1, :cond_11

    const-string p0, &quot;phoneNo is empty return null &quot;

    .line 2
    invoke-static {v2, p0}, Landroid/util/Log;-&amp;gt;i(Ljava/lang/String;Ljava/lang/String;)I

    return-object v3

    :cond_11
    const-string v1, &quot;-&quot;

    const-string v4, &quot;&quot;

    .line 3
    invoke-virtual {p1, v1, v4}, Ljava/lang/String;-&amp;gt;replace(Ljava/lang/CharSequence;Ljava/lang/CharSequence;)Ljava/lang/String;

    move-result-object p1

    const-string v5, &quot; &quot;

    invoke-virtual {p1, v5, v4}, Ljava/lang/String;-&amp;gt;replace(Ljava/lang/CharSequence;Ljava/lang/CharSequence;)Ljava/lang/String;

    move-result-object p1

    .line 4
    invoke-static {p1}, Landroid/text/TextUtils;-&amp;gt;isEmpty(Ljava/lang/CharSequence;)Z

    move-result v5

    if-eqz v5, :cond_26

    return-object v3

    .line 5
    :cond_26
    iget-object v5, p0, Lcom/oplus/phonenoareainquire/PhoneNoInquireProvider;-&amp;gt;l:Ljava/util/ArrayList;

    if-nez v5, :cond_30

    .line 6
    invoke-static {}, Lcom/oplus/phonenoareainquire/PhoneNoInquireProvider;-&amp;gt;i()Ljava/util/ArrayList;

    move-result-object v5

    iput-object v5, p0, Lcom/oplus/phonenoareainquire/PhoneNoInquireProvider;-&amp;gt;l:Ljava/util/ArrayList;

    :cond_30
    const/4 v5, 0x0

    move v6, v5

    .line 7
    :goto_32
    iget-object v7, p0, Lcom/oplus/phonenoareainquire/PhoneNoInquireProvider;-&amp;gt;l:Ljava/util/ArrayList;

    invoke-virtual {v7}, Ljava/util/ArrayList;-&amp;gt;size()I

    move-result v7

    if-ge v6, v7, :cond_6c

    .line 8
    iget-object v7, p0, Lcom/oplus/phonenoareainquire/PhoneNoInquireProvider;-&amp;gt;l:Ljava/util/ArrayList;

    invoke-virtual {v7, v6}, Ljava/util/ArrayList;-&amp;gt;get(I)Ljava/lang/Object;

    move-result-object v7

    check-cast v7, Ljava/lang/String;

    invoke-virtual {p1, v7}, Ljava/lang/String;-&amp;gt;startsWith(Ljava/lang/String;)Z

    move-result v7

    if-eqz v7, :cond_69

    .line 9
    new-instance v7, Ljava/lang/StringBuilder;

    invoke-direct {v7}, Ljava/lang/StringBuilder;-&amp;gt;&amp;lt;init&amp;gt;()V

    const-string v8, &quot;+&quot;

    invoke-virtual {v7, v8}, Ljava/lang/StringBuilder;-&amp;gt;append(Ljava/lang/String;)Ljava/lang/StringBuilder;

    iget-object v8, p0, Lcom/oplus/phonenoareainquire/PhoneNoInquireProvider;-&amp;gt;l:Ljava/util/ArrayList;

    invoke-virtual {v8, v6}, Ljava/util/ArrayList;-&amp;gt;get(I)Ljava/lang/Object;

    move-result-object v8

    check-cast v8, Ljava/lang/String;

    invoke-virtual {v8}, Ljava/lang/String;-&amp;gt;length()I

    move-result v8

    invoke-virtual {p1, v8}, Ljava/lang/String;-&amp;gt;substring(I)Ljava/lang/String;

    move-result-object p1

    invoke-virtual {v7, p1}, Ljava/lang/StringBuilder;-&amp;gt;append(Ljava/lang/String;)Ljava/lang/StringBuilder;

    invoke-virtual {v7}, Ljava/lang/StringBuilder;-&amp;gt;toString()Ljava/lang/String;

    move-result-object p1

    :cond_69
    add-int/lit8 v6, v6, 0x1

    goto :goto_32

    .line 10
    :cond_6c
    iget-object v6, p0, Lcom/oplus/phonenoareainquire/PhoneNoInquireProvider;-&amp;gt;k:Ljava/util/ArrayList;

    if-nez v6, :cond_7a

    .line 11
    invoke-virtual {p0}, Landroid/content/ContentProvider;-&amp;gt;getContext()Landroid/content/Context;

    move-result-object v6

    invoke-static {v6}, Lcom/oplus/phonenoareainquire/PhoneNoInquireProvider;-&amp;gt;x(Landroid/content/Context;)Ljava/util/ArrayList;

    move-result-object v6

    iput-object v6, p0, Lcom/oplus/phonenoareainquire/PhoneNoInquireProvider;-&amp;gt;k:Ljava/util/ArrayList;

    :cond_7a
    move v6, v5

    .line 12
    :goto_7b
    iget-object v7, p0, Lcom/oplus/phonenoareainquire/PhoneNoInquireProvider;-&amp;gt;k:Ljava/util/ArrayList;

    invoke-virtual {v7}, Ljava/util/ArrayList;-&amp;gt;size()I

    move-result v7

    const/4 v8, 0x1

    if-ge v6, v7, :cond_13f

    .line 13
    iget-object v7, p0, Lcom/oplus/phonenoareainquire/PhoneNoInquireProvider;-&amp;gt;k:Ljava/util/ArrayList;

    invoke-virtual {v7, v6}, Ljava/util/ArrayList;-&amp;gt;get(I)Ljava/lang/Object;

    move-result-object v7

    check-cast v7, Ljava/lang/String;

    invoke-virtual {p1, v7}, Ljava/lang/String;-&amp;gt;startsWith(Ljava/lang/String;)Z

    move-result v7

    if-eqz v7, :cond_13b

    .line 14
    iget-object v7, p0, Lcom/oplus/phonenoareainquire/PhoneNoInquireProvider;-&amp;gt;k:Ljava/util/ArrayList;

    invoke-virtual {v7, v6}, Ljava/util/ArrayList;-&amp;gt;get(I)Ljava/lang/Object;

    move-result-object v7

    check-cast v7, Ljava/lang/String;

    invoke-virtual {v7}, Ljava/lang/String;-&amp;gt;length()I

    move-result v7

    invoke-virtual {p1, v7}, Ljava/lang/String;-&amp;gt;substring(I)Ljava/lang/String;

    move-result-object p1

    .line 15
    invoke-static {p1}, Landroid/text/TextUtils;-&amp;gt;isEmpty(Ljava/lang/CharSequence;)Z

    move-result v7

    if-nez v7, :cond_13f

    iget-object v7, p0, Lcom/oplus/phonenoareainquire/PhoneNoInquireProvider;-&amp;gt;k:Ljava/util/ArrayList;

    .line 16
    invoke-virtual {v7, v6}, Ljava/util/ArrayList;-&amp;gt;get(I)Ljava/lang/Object;

    move-result-object v7

    check-cast v7, Ljava/lang/String;

    const-string v9, &quot;+86&quot;

    invoke-virtual {v7, v9}, Ljava/lang/String;-&amp;gt;equals(Ljava/lang/Object;)Z

    move-result v7

    if-nez v7, :cond_c8

    iget-object v7, p0, Lcom/oplus/phonenoareainquire/PhoneNoInquireProvider;-&amp;gt;k:Ljava/util/ArrayList;

    invoke-virtual {v7, v6}, Ljava/util/ArrayList;-&amp;gt;get(I)Ljava/lang/Object;

    move-result-object v6

    check-cast v6, Ljava/lang/String;

    const-string v7, &quot;0086&quot;

    invoke-virtual {v6, v7}, Ljava/lang/String;-&amp;gt;equals(Ljava/lang/Object;)Z

    move-result v6

    if-eqz v6, :cond_13f

    :cond_c8
    invoke-virtual {p1}, Ljava/lang/String;-&amp;gt;length()I

    move-result v6

    const/4 v7, 0x6

    if-lt v6, v7, :cond_13f

    move v6, v5

    .line 17
    :goto_d0
    :try_start_d0
    iget-object v7, p0, Lcom/oplus/phonenoareainquire/PhoneNoInquireProvider;-&amp;gt;i:Ljava/util/ArrayList;

    invoke-virtual {v7}, Ljava/util/ArrayList;-&amp;gt;size()I

    move-result v7

    if-ge v6, v7, :cond_112

    .line 18
    iget-object v7, p0, Lcom/oplus/phonenoareainquire/PhoneNoInquireProvider;-&amp;gt;i:Ljava/util/ArrayList;

    invoke-virtual {v7, v6}, Ljava/util/ArrayList;-&amp;gt;get(I)Ljava/lang/Object;

    move-result-object v7

    check-cast v7, Ljava/lang/String;

    .line 19
    invoke-static {v7}, Landroid/text/TextUtils;-&amp;gt;isEmpty(Ljava/lang/CharSequence;)Z

    move-result v9

    if-nez v9, :cond_fc

    invoke-virtual {v7, v0}, Ljava/lang/String;-&amp;gt;startsWith(Ljava/lang/String;)Z

    move-result v9

    if-eqz v9, :cond_fc

    .line 20
    invoke-virtual {p1, v7}, Ljava/lang/String;-&amp;gt;startsWith(Ljava/lang/String;)Z

    move-result v7

    if-eqz v7, :cond_fc

    invoke-virtual {p1}, Ljava/lang/String;-&amp;gt;length()I

    move-result v7
    :try_end_f6
    .catch Ljava/lang/Exception; {:try_start_d0 .. :try_end_f6} :catch_ff

    const/16 v9, 0xa

    if-eq v7, v9, :cond_fc

    move v6, v5

    goto :goto_113

    :cond_fc
    add-int/lit8 v6, v6, 0x1

    goto :goto_d0

    :catch_ff
    move-exception v6

    .line 21
    new-instance v7, Ljava/lang/StringBuilder;

    invoke-direct {v7}, Ljava/lang/StringBuilder;-&amp;gt;&amp;lt;init&amp;gt;()V

    invoke-virtual {v7, v4}, Ljava/lang/StringBuilder;-&amp;gt;append(Ljava/lang/String;)Ljava/lang/StringBuilder;

    invoke-virtual {v7, v6}, Ljava/lang/StringBuilder;-&amp;gt;append(Ljava/lang/Object;)Ljava/lang/StringBuilder;

    invoke-virtual {v7}, Ljava/lang/StringBuilder;-&amp;gt;toString()Ljava/lang/String;

    move-result-object v6

    invoke-static {v2, v6}, Landroid/util/Log;-&amp;gt;e(Ljava/lang/String;Ljava/lang/String;)I

    :cond_112
    move v6, v8

    :goto_113
    const-string v7, &quot;0&quot;

    if-eqz v6, :cond_11d

    .line 22
    invoke-virtual {p1, v0}, Ljava/lang/String;-&amp;gt;startsWith(Ljava/lang/String;)Z

    move-result v0

    if-nez v0, :cond_12b

    .line 23
    :cond_11d
    invoke-virtual {p1, v7}, Ljava/lang/String;-&amp;gt;startsWith(Ljava/lang/String;)Z

    move-result v0

    if-nez v0, :cond_13f

    const-string v0, &quot;1&quot;

    invoke-virtual {p1, v0}, Ljava/lang/String;-&amp;gt;startsWith(Ljava/lang/String;)Z

    move-result v0

    if-nez v0, :cond_13f

    .line 24
    :cond_12b
    new-instance v0, Ljava/lang/StringBuilder;

    invoke-direct {v0}, Ljava/lang/StringBuilder;-&amp;gt;&amp;lt;init&amp;gt;()V

    invoke-virtual {v0, v7}, Ljava/lang/StringBuilder;-&amp;gt;append(Ljava/lang/String;)Ljava/lang/StringBuilder;

    invoke-virtual {v0, p1}, Ljava/lang/StringBuilder;-&amp;gt;append(Ljava/lang/String;)Ljava/lang/StringBuilder;

    invoke-virtual {v0}, Ljava/lang/StringBuilder;-&amp;gt;toString()Ljava/lang/String;

    move-result-object p1

    goto :goto_13f

    :cond_13b
    add-int/lit8 v6, v6, 0x1

    goto/16 :goto_7b

    .line 25
    :cond_13f
    :goto_13f
    invoke-static {p1}, Landroid/text/TextUtils;-&amp;gt;isEmpty(Ljava/lang/CharSequence;)Z

    move-result v0

    const/16 v6, 0x30

    const/4 v7, 0x2

    const/4 v9, 0x3

    if-nez v0, :cond_161

    invoke-virtual {p1}, Ljava/lang/String;-&amp;gt;length()I

    move-result v0

    if-le v0, v9, :cond_161

    const-string v0, &quot;01&quot;

    .line 26
    invoke-virtual {p1, v0}, Ljava/lang/String;-&amp;gt;startsWith(Ljava/lang/String;)Z

    move-result v0

    if-eqz v0, :cond_161

    invoke-virtual {p1, v7}, Ljava/lang/String;-&amp;gt;charAt(I)C

    move-result v0

    if-eq v0, v6, :cond_161

    .line 27
    invoke-virtual {p1, v8}, Ljava/lang/String;-&amp;gt;substring(I)Ljava/lang/String;

    move-result-object p1

    :cond_161
    if-eqz p1, :cond_32e

    .line 28
    invoke-virtual {p1}, Ljava/lang/String;-&amp;gt;length()I

    move-result v0

    if-nez v0, :cond_16b

    goto/16 :goto_32e

    .line 29
    :cond_16b
    :try_start_16b
    invoke-virtual {p1}, Ljava/lang/String;-&amp;gt;length()I

    move-result v0

    move v10, v5

    :goto_170
    const/4 v11, 0x7

    if-ge v10, v0, :cond_186

    if-ge v10, v11, :cond_186

    const-string v11, &quot;0123456789-&quot;

    .line 30
    invoke-virtual {p1, v10}, Ljava/lang/String;-&amp;gt;charAt(I)C

    move-result v12

    invoke-virtual {v11, v12}, Ljava/lang/String;-&amp;gt;indexOf(I)I

    move-result v11

    const/4 v12, -0x1

    if-ne v11, v12, :cond_183

    return-object v3

    :cond_183
    add-int/lit8 v10, v10, 0x1

    goto :goto_170

    .line 31
    :cond_186
    invoke-virtual {p1, v1, v4}, Ljava/lang/String;-&amp;gt;replace(Ljava/lang/CharSequence;Ljava/lang/CharSequence;)Ljava/lang/String;

    move-result-object p1

    .line 32
    invoke-virtual {p1}, Ljava/lang/String;-&amp;gt;length()I

    move-result v0

    if-nez v0, :cond_196

    const-string p0, &quot;Regular telephone number\&apos;s length is 0 return&quot;

    .line 33
    invoke-static {v2, p0}, Landroid/util/Log;-&amp;gt;i(Ljava/lang/String;Ljava/lang/String;)I

    return-object v3

    .line 34
    :cond_196
    invoke-virtual {p1, v5}, Ljava/lang/String;-&amp;gt;charAt(I)C

    move-result v0

    const/16 v1, 0x31

    const/4 v10, 0x4

    if-ne v0, v6, :cond_1d5

    .line 35
    invoke-virtual {p1}, Ljava/lang/String;-&amp;gt;length()I

    move-result v0

    if-ge v0, v9, :cond_1a6

    return-object v3

    .line 36
    :cond_1a6
    invoke-virtual {p1, v8}, Ljava/lang/String;-&amp;gt;charAt(I)C

    move-result v0

    if-eq v0, v1, :cond_1c1

    invoke-virtual {p1, v8}, Ljava/lang/String;-&amp;gt;charAt(I)C

    move-result v0

    const/16 v1, 0x32

    if-ne v0, v1, :cond_1b5

    goto :goto_1c1

    .line 37
    :cond_1b5
    invoke-virtual {p1}, Ljava/lang/String;-&amp;gt;length()I

    move-result v0

    if-ge v0, v10, :cond_1bc

    return-object v3

    .line 38
    :cond_1bc
    invoke-virtual {p1, v5, v10}, Ljava/lang/String;-&amp;gt;substring(II)Ljava/lang/String;

    move-result-object p1

    goto :goto_1c5

    .line 39
    :cond_1c1
    :goto_1c1
    invoke-virtual {p1, v5, v9}, Ljava/lang/String;-&amp;gt;substring(II)Ljava/lang/String;

    move-result-object p1

    .line 40
    :goto_1c5
    sget-object v0, Lcom/oplus/phonenoareainquire/PhoneNoInquireProvider;-&amp;gt;s:Landroid/net/Uri;

    invoke-static {v0, p1}, Landroid/net/Uri;-&amp;gt;withAppendedPath(Landroid/net/Uri;Ljava/lang/String;)Landroid/net/Uri;

    move-result-object v5

    const/4 v6, 0x0

    const/4 v7, 0x0

    const/4 v8, 0x0

    const/4 v9, 0x0

    move-object v4, p0

    .line 41
    invoke-virtual/range {v4 .. v9}, Lcom/oplus/phonenoareainquire/PhoneNoInquireProvider;-&amp;gt;query(Landroid/net/Uri;[Ljava/lang/String;Ljava/lang/String;[Ljava/lang/String;Ljava/lang/String;)Landroid/database/Cursor;

    move-result-object p0

    return-object p0

    .line 42
    :cond_1d5
    invoke-virtual {p1, v5}, Ljava/lang/String;-&amp;gt;charAt(I)C

    move-result v0

    if-ne v0, v1, :cond_317

    .line 43
    invoke-virtual {p1}, Ljava/lang/String;-&amp;gt;length()I

    move-result v0
    :try_end_1df
    .catch Ljava/lang/Exception; {:try_start_16b .. :try_end_1df} :catch_318

    if-ge v0, v11, :cond_1e2

    return-object v3

    :cond_1e2
    move v0, v5

    .line 44
    :goto_1e3
    :try_start_1e3
    iget-object v1, p0, Lcom/oplus/phonenoareainquire/PhoneNoInquireProvider;-&amp;gt;i:Ljava/util/ArrayList;

    invoke-virtual {v1}, Ljava/util/ArrayList;-&amp;gt;size()I

    move-result v1

    if-ge v0, v1, :cond_233

    .line 45
    iget-object v1, p0, Lcom/oplus/phonenoareainquire/PhoneNoInquireProvider;-&amp;gt;i:Ljava/util/ArrayList;

    invoke-virtual {v1, v0}, Ljava/util/ArrayList;-&amp;gt;get(I)Ljava/lang/Object;

    move-result-object v1

    check-cast v1, Ljava/lang/String;

    .line 46
    invoke-static {v1}, Landroid/text/TextUtils;-&amp;gt;isEmpty(Ljava/lang/CharSequence;)Z

    move-result v6

    if-nez v6, :cond_230

    invoke-virtual {p1, v1}, Ljava/lang/String;-&amp;gt;startsWith(Ljava/lang/String;)Z

    move-result v6

    if-eqz v6, :cond_230

    .line 47
    iget-object v0, p0, Lcom/oplus/phonenoareainquire/PhoneNoInquireProvider;-&amp;gt;c:Ljava/util/HashMap;

    invoke-virtual {v0, v1}, Ljava/util/HashMap;-&amp;gt;get(Ljava/lang/Object;)Ljava/lang/Object;

    move-result-object v0

    check-cast v0, Ljava/lang/Integer;

    if-nez v0, :cond_20a

    return-object v3

    .line 48
    :cond_20a
    invoke-virtual {p1}, Ljava/lang/String;-&amp;gt;length()I

    move-result v6

    invoke-virtual {v0}, Ljava/lang/Integer;-&amp;gt;intValue()I

    move-result v12

    if-ge v6, v12, :cond_215

    return-object v3

    .line 49
    :cond_215
    invoke-virtual {v0}, Ljava/lang/Integer;-&amp;gt;intValue()I

    move-result v0

    invoke-virtual {p1, v5, v0}, Ljava/lang/String;-&amp;gt;substring(II)Ljava/lang/String;

    move-result-object v0

    .line 50
    invoke-virtual {v1}, Ljava/lang/String;-&amp;gt;length()I

    move-result v6

    invoke-virtual {v0, v5, v6}, Ljava/lang/String;-&amp;gt;substring(II)Ljava/lang/String;

    move-result-object v6
    :try_end_225
    .catch Ljava/lang/Exception; {:try_start_1e3 .. :try_end_225} :catch_237

    .line 51
    :try_start_225
    invoke-virtual {v1}, Ljava/lang/String;-&amp;gt;length()I

    move-result v1

    invoke-virtual {v0, v1}, Ljava/lang/String;-&amp;gt;substring(I)Ljava/lang/String;

    move-result-object v1
    :try_end_22d
    .catch Ljava/lang/Exception; {:try_start_225 .. :try_end_22d} :catch_22e

    goto :goto_24d

    :catch_22e
    move-exception v0

    goto :goto_239

    :cond_230
    add-int/lit8 v0, v0, 0x1

    goto :goto_1e3

    :cond_233
    move-object v0, v3

    move-object v1, v0

    move-object v6, v1

    goto :goto_24d

    :catch_237
    move-exception v0

    move-object v6, v3

    .line 52
    :goto_239
    :try_start_239
    new-instance v1, Ljava/lang/StringBuilder;

    invoke-direct {v1}, Ljava/lang/StringBuilder;-&amp;gt;&amp;lt;init&amp;gt;()V

    invoke-virtual {v1, v4}, Ljava/lang/StringBuilder;-&amp;gt;append(Ljava/lang/String;)Ljava/lang/StringBuilder;

    invoke-virtual {v1, v0}, Ljava/lang/StringBuilder;-&amp;gt;append(Ljava/lang/Object;)Ljava/lang/StringBuilder;

    invoke-virtual {v1}, Ljava/lang/StringBuilder;-&amp;gt;toString()Ljava/lang/String;

    move-result-object v0

    invoke-static {v2, v0}, Landroid/util/Log;-&amp;gt;e(Ljava/lang/String;Ljava/lang/String;)I

    move-object v0, v3

    move-object v1, v0

    :goto_24d
    if-nez v0, :cond_25b

    .line 53
    invoke-virtual {p1, v5, v11}, Ljava/lang/String;-&amp;gt;substring(II)Ljava/lang/String;

    move-result-object v0

    .line 54
    invoke-virtual {v0, v5, v9}, Ljava/lang/String;-&amp;gt;substring(II)Ljava/lang/String;

    move-result-object v6

    .line 55
    invoke-virtual {v0, v9}, Ljava/lang/String;-&amp;gt;substring(I)Ljava/lang/String;

    move-result-object v1

    .line 56
    :cond_25b
    iget-object v0, p0, Lcom/oplus/phonenoareainquire/PhoneNoInquireProvider;-&amp;gt;a:Ljava/util/HashMap;

    invoke-virtual {v0, v6}, Ljava/util/HashMap;-&amp;gt;get(Ljava/lang/Object;)Ljava/lang/Object;

    move-result-object v0

    check-cast v0, Ljava/lang/Integer;

    if-nez v0, :cond_27e

    .line 57
    new-instance v0, Ljava/lang/StringBuilder;

    invoke-direct {v0}, Ljava/lang/StringBuilder;-&amp;gt;&amp;lt;init&amp;gt;()V

    const-string v1, &quot;prefix == null return number = &quot;

    invoke-virtual {v0, v1}, Ljava/lang/StringBuilder;-&amp;gt;append(Ljava/lang/String;)Ljava/lang/StringBuilder;

    invoke-direct {p0, p1}, Lcom/oplus/phonenoareainquire/PhoneNoInquireProvider;-&amp;gt;G(Ljava/lang/String;)Ljava/lang/String;

    move-result-object p0

    invoke-virtual {v0, p0}, Ljava/lang/StringBuilder;-&amp;gt;append(Ljava/lang/String;)Ljava/lang/StringBuilder;

    invoke-virtual {v0}, Ljava/lang/StringBuilder;-&amp;gt;toString()Ljava/lang/String;

    move-result-object p0

    invoke-static {v2, p0}, Landroid/util/Log;-&amp;gt;d(Ljava/lang/String;Ljava/lang/String;)I

    return-object v3

    .line 58
    :cond_27e
    invoke-virtual {v0}, Ljava/lang/Integer;-&amp;gt;intValue()I

    move-result p1

    invoke-static {v1}, Ljava/lang/Integer;-&amp;gt;parseInt(Ljava/lang/String;)I

    move-result v0

    add-int/2addr p1, v0

    .line 59
    rem-int/lit8 v0, p1, 0x2

    if-eqz v0, :cond_292

    add-int/lit8 p1, p1, -0x1

    if-gez p1, :cond_290

    move p1, v5

    :cond_290
    move v0, v8

    goto :goto_293

    :cond_292
    move v0, v5

    :goto_293
    shr-int/2addr p1, v8

    mul-int/2addr p1, v9

    .line 60
    iget-object v1, p0, Lcom/oplus/phonenoareainquire/PhoneNoInquireProvider;-&amp;gt;b:[B

    aget-byte v4, v1, p1

    and-int/lit16 v4, v4, 0xff

    add-int/lit8 v6, p1, 0x1

    .line 61
    aget-byte v6, v1, v6

    and-int/lit16 v6, v6, 0xff

    add-int/2addr p1, v7

    .line 62
    aget-byte p1, v1, p1

    and-int/lit16 p1, p1, 0xff

    shl-int/lit8 v1, v4, 0x4

    shr-int/lit8 v4, v6, 0x4

    or-int/2addr v1, v4

    and-int/lit8 v4, v6, 0xf

    shl-int/lit8 v4, v4, 0x8

    or-int/2addr p1, v4

    if-eqz v0, :cond_2b3

    move v1, p1

    :cond_2b3
    add-int/2addr v1, v8

    if-ne v1, v8, :cond_2b7

    return-object v3

    .line 63
    :cond_2b7
    invoke-static {v1}, Ljava/lang/String;-&amp;gt;valueOf(I)Ljava/lang/String;

    move-result-object p1

    .line 64
    iget-object v0, p0, Lcom/oplus/phonenoareainquire/PhoneNoInquireProvider;-&amp;gt;j:Lcom/oplus/phonenoareainquire/a;

    if-eqz v0, :cond_300

    .line 65
    invoke-virtual {v0, p1}, Lcom/oplus/phonenoareainquire/a;-&amp;gt;b(Ljava/lang/String;)Lcom/oplus/phonenoareainquire/a$a;

    move-result-object v0

    if-eqz v0, :cond_300

    .line 66
    invoke-virtual {v0}, Lcom/oplus/phonenoareainquire/a$a;-&amp;gt;a()Ljava/lang/String;

    move-result-object v4

    invoke-static {v4}, Landroid/text/TextUtils;-&amp;gt;isEmpty(Ljava/lang/CharSequence;)Z

    move-result v4

    if-nez v4, :cond_300

    invoke-virtual {v0}, Lcom/oplus/phonenoareainquire/a$a;-&amp;gt;b()Ljava/lang/String;

    move-result-object v4

    invoke-static {v4}, Landroid/text/TextUtils;-&amp;gt;isEmpty(Ljava/lang/CharSequence;)Z

    move-result v4

    if-nez v4, :cond_300

    .line 67
    new-instance p0, Landroid/database/MatrixCursor;

    new-array v1, v9, [Ljava/lang/String;

    const-string v4, &quot;_id&quot;

    aput-object v4, v1, v5

    const-string v4, &quot;areano&quot;

    aput-object v4, v1, v8

    const-string v4, &quot;cityname&quot;

    aput-object v4, v1, v7

    invoke-direct {p0, v1, v8}, Landroid/database/MatrixCursor;-&amp;gt;&amp;lt;init&amp;gt;([Ljava/lang/String;I)V

    new-array v1, v9, [Ljava/lang/String;

    aput-object p1, v1, v5

    .line 68
    invoke-virtual {v0}, Lcom/oplus/phonenoareainquire/a$a;-&amp;gt;a()Ljava/lang/String;

    move-result-object p1

    aput-object p1, v1, v8

    invoke-virtual {v0}, Lcom/oplus/phonenoareainquire/a$a;-&amp;gt;b()Ljava/lang/String;

    move-result-object p1

    aput-object p1, v1, v7

    invoke-virtual {p0, v1}, Landroid/database/MatrixCursor;-&amp;gt;addRow([Ljava/lang/Object;)V

    return-object p0

    .line 69
    :cond_300
    sget-object p1, Lcom/oplus/phonenoareainquire/PhoneNoInquireProvider;-&amp;gt;s:Landroid/net/Uri;

    .line 70
    invoke-static {v1}, Ljava/lang/Integer;-&amp;gt;toString(I)Ljava/lang/String;

    move-result-object v0

    .line 71
    invoke-static {p1, v0}, Landroid/net/Uri;-&amp;gt;withAppendedPath(Landroid/net/Uri;Ljava/lang/String;)Landroid/net/Uri;

    move-result-object v5

    const/4 v6, 0x0

    .line 72
    invoke-static {v1}, Ljava/lang/Integer;-&amp;gt;toString(I)Ljava/lang/String;

    move-result-object v7

    const/4 v8, 0x0

    const/4 v9, 0x0

    move-object v4, p0

    invoke-virtual/range {v4 .. v9}, Lcom/oplus/phonenoareainquire/PhoneNoInquireProvider;-&amp;gt;query(Landroid/net/Uri;[Ljava/lang/String;Ljava/lang/String;[Ljava/lang/String;Ljava/lang/String;)Landroid/database/Cursor;

    move-result-object p0
    :try_end_316
    .catch Ljava/lang/Exception; {:try_start_239 .. :try_end_316} :catch_318

    return-object p0

    :cond_317
    return-object v3

    :catch_318
    move-exception p0

    .line 73
    new-instance p1, Ljava/lang/StringBuilder;

    invoke-direct {p1}, Ljava/lang/StringBuilder;-&amp;gt;&amp;lt;init&amp;gt;()V

    const-string v0, &quot;e = &quot;

    invoke-virtual {p1, v0}, Ljava/lang/StringBuilder;-&amp;gt;append(Ljava/lang/String;)Ljava/lang/StringBuilder;

    invoke-virtual {p1, p0}, Ljava/lang/StringBuilder;-&amp;gt;append(Ljava/lang/Object;)Ljava/lang/StringBuilder;

    invoke-virtual {p1}, Ljava/lang/StringBuilder;-&amp;gt;toString()Ljava/lang/String;

    move-result-object p0

    invoke-static {v2, p0}, Landroid/util/Log;-&amp;gt;e(Ljava/lang/String;Ljava/lang/String;)I

    return-object v3

    :cond_32e
    :goto_32e
    const-string p0, &quot;num is null or length is 0 return null &quot;

    .line 74
    invoke-static {v2, p0}, Landroid/util/Log;-&amp;gt;i(Ljava/lang/String;Ljava/lang/String;)I

    return-object v3
.end method
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;当系统需要查询一个具体的号码（例如 &lt;code&gt;13812345678&lt;/code&gt;）时，&lt;code&gt;l()&lt;/code&gt; 方法的剥离与寻址逻辑如下：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;提取核心&lt;/strong&gt;：截取前 7 位，得到 &lt;code&gt;1381234&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;拆分前后缀&lt;/strong&gt;：前缀 Prefix = &lt;code&gt;138&lt;/code&gt;，后缀 Suffix = &lt;code&gt;1234&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;计算绝对索引&lt;/strong&gt;：
去 &lt;code&gt;HashMap&lt;/code&gt; 中查到 &lt;code&gt;138&lt;/code&gt; 的基础偏移量（假设为 &lt;code&gt;80000&lt;/code&gt;）。
将其与后缀转换为的整数相加：&lt;code&gt;绝对索引 = 80000 + 1234 = 81234&lt;/code&gt;。&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;4.3 精妙的 12-Bit 极限压缩算法&lt;/h3&gt;
&lt;p&gt;拿到绝对索引后，如何去庞大的二进制流中取出归属地 ID？
通常，表示一个城市的 ID 至少需要一个 &lt;code&gt;short&lt;/code&gt; (16位/2字节)。但为了将千万级号段的数据体积压缩到极致，工程师&lt;strong&gt;为每个城市 ID 仅分配了 12 个 Bit (1.5 字节)&lt;/strong&gt;。因为全国地级市不到 400 个，最大 ID 只需要 12 位二进制（最大可表示 4095）便绰绰有余。&lt;/p&gt;
&lt;p&gt;为了将两个 12-Bit 的数据严丝合缝地塞进 3 个字节（24 bits）里，底层进行了绝妙的位移运算（Bitwise Shift）。将 Smali 代码还原为 Java 逻辑如下：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;int remainder = index % 2;
int baseIndex = (index / 2) * 3; // 因为每 2 个数据共占 3 个字节

// 连续读取 3 个字节
int b1 = this.b[baseIndex] &amp;amp; 0xFF;
int b2 = this.b[baseIndex + 1] &amp;amp; 0xFF;
int b3 = this.b[baseIndex + 2] &amp;amp; 0xFF;

int cityId;
if (remainder == 0) {
    // 偶数索引：取第1个字节的全部 + 第2个字节的前4位
    cityId = (b1 &amp;lt;&amp;lt; 4) | (b2 &amp;gt;&amp;gt; 4);
} else {
    // 奇数索引：取第2个字节的后4位 + 第3个字节的全部
    cityId = ((b2 &amp;amp; 0x0F) &amp;lt;&amp;lt; 8) | b3;
}

// cityId 为 0 时表示未知归属地
if (cityId == 0) { 
    return null; 
}

&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;拿到解密后的 &lt;code&gt;cityId&lt;/code&gt; 后，直接将其作为索引，去步骤 3 中提取出的城市字典列表中查找，即可完美获得该号码的对应城市与区号。&lt;/p&gt;
&lt;h2&gt;5. Python 算法重构&lt;/h2&gt;
&lt;p&gt;基于以上的逆向分析，我们完全脱离了 Android 环境，使用纯 Python 实现了对该二进制数据文件的脱机解析与查询。完整代码如下：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;import os

def load_database(file_path):
    print(&quot;⏳ 正在加载并解析底层数据库...&quot;)
    with open(file_path, &apos;rb&apos;) as f:
        data = f.read()

    # 1. 解析城市字典 (尾部 12002 字节)
    tail_data = data[-12002:]
    area_codes_raw = tail_data[2:2002]
    city_names_raw = tail_data[2002:10002]
    extend_prefix_raw = tail_data[10002:12002]

    cities = []
    for i in range(400):
        # 解析区号
        area = area_codes_raw[i*5 : i*5+5].decode(&apos;ascii&apos;, errors=&apos;ignore&apos;).strip()
        # 解析城市名 (GBK编码，遇 \x00 截断)
        name_bytes = city_names_raw[i*20 : i*20+20].split(b&apos;\x00&apos;)[0]
        name = name_bytes.decode(&apos;gbk&apos;, errors=&apos;ignore&apos;).strip()
        cities.append((area, name))

    # 2. 构建号段偏移映射表 
    prefix_map = {}
    base_idx = 0

    # 基础号段 130-139, 150-159
    for p in range(130, 140): prefix_map[str(p)] = base_idx; base_idx += 10000
    for p in range(150, 160): prefix_map[str(p)] = base_idx; base_idx += 10000

    # 特殊基础号段 188, 189
    prefix_map[&quot;188&quot;] = base_idx; base_idx += 10000
    prefix_map[&quot;189&quot;] = base_idx; base_idx += 10000

    # 扩展号段
    for i in range(1000):
        b1 = extend_prefix_raw[i*2]
        b2 = extend_prefix_raw[i*2 + 1]
        prefix_val = (b1 &amp;lt;&amp;lt; 8) | b2
        if prefix_val == 0:
            break
        prefix_map[str(prefix_val)] = base_idx
        base_idx += 10000

    # 3. 提取核心二进制映射区 (跳过头部16字节，去掉尾部12002字节)
    binary_array = data[16 : -12002]
    print(f&quot;✅ 数据库加载成功！共解析出 {len(prefix_map)} 个号段。&quot;)
    return prefix_map, cities, binary_array


def query_phone(phone_7, prefix_map, cities, binary_array):
    if len(phone_7) != 7 or not phone_7.isdigit():
        return &quot;❌ 格式错误：请输入纯数字的 7 位号码前缀！&quot;

    prefix = phone_7[:3]
    suffix = phone_7[3:]

    if prefix not in prefix_map:
        return f&quot;❓ 未知号段：数据库中不存在 {prefix} 号段&quot;

    # 计算绝对索引
    base_index = prefix_map[prefix]
    absolute_index = base_index + int(suffix)

    # 1.5 字节对齐读取算法：每 2 个索引占用 3 个字节
    byte_offset = (absolute_index // 2) * 3

    if byte_offset + 2 &amp;gt;= len(binary_array):
        return &quot;⚠️ 数据越界：该号码超出了数据库核心区范围&quot;

    b1 = binary_array[byte_offset]
    b2 = binary_array[byte_offset + 1]
    b3 = binary_array[byte_offset + 2]

    # 解码 12-Bit 城市 ID
    if absolute_index % 2 == 0:
        city_id = (b1 &amp;lt;&amp;lt; 4) | (b2 &amp;gt;&amp;gt; 4)
    else:
        city_id = ((b2 &amp;amp; 0x0F) &amp;lt;&amp;lt; 8) | b3

    if city_id == 0:
        return &quot;📍 归属地未知 (系统中无此记录)&quot;

    list_index = city_id 
    if list_index &amp;gt;= len(cities) or list_index &amp;lt; 0:
        return f&quot;⚠️ 数据异常：解析出未知的城市 ID ({city_id})&quot;

    area_code, city_name = cities[list_index]
    if not city_name:
        return &quot;📍 归属地未知 (城市字段为空)&quot;

    return f&quot;📍 归属地: 【{city_name}】 (长途区号: {area_code})&quot;


def main():
    file_name = &quot;PhoneNumberData_3_1_0.dat&quot;
    if not os.path.exists(file_name):
        print(f&quot;❌ 找不到文件：{file_name}&quot;)
        return

    prefix_map, cities, binary_array = load_database(file_name)

    print(&quot;\n&quot; + &quot;=&quot;*40)
    print(&quot;📞 ColorOS 离线号码归属地查询系统&quot;)
    print(&quot;=&quot;*40)
    
    while True:
        try:
            user_input = input(&quot;\n👉 请输入 7 位手机号码前缀 (输入 q 退出): &quot;).strip()
            if user_input.lower() == &apos;q&apos;:
                break
            
            if len(user_input) &amp;gt;= 7:
                user_input = user_input[:7]
                
            result = query_phone(user_input, prefix_map, cities, binary_array)
            print(result)
            
        except KeyboardInterrupt:
            break
        except Exception as e:
            print(f&quot;发生错误: {e}&quot;)

&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;6. 阶段总结与预告&lt;/h2&gt;
&lt;p&gt;至此，我们已经成功解决了字典的内存偏移规则、精妙的 12-Bit 压缩解密算法，以及尾部城市的解析方式，完成了号码归属地的逆向重构。&lt;/p&gt;
&lt;p&gt;不过，你可能会发现，这套方案目前只能查到归属城市，还缺少至关重要的“运营商”信息。在下一节中，我们将继续深挖同目录下的 &lt;code&gt;CarrierData_1_0.dat&lt;/code&gt;，揭开运营商识别的底层多级指针寻址机制，敬请期待！&lt;/p&gt;
</content:encoded></item><item><title>2025：经历的意义在于引导，而非定义</title><link>https://006lp.de/posts/2025-experiences-guide-not-define/</link><guid isPermaLink="true">https://006lp.de/posts/2025-experiences-guide-not-define/</guid><description>“我渴望拯救别人，后来才发现，我想拯救的不过是黑暗中的自己。” 2025，从迷茫、自我厌恶到触底反弹。是《无职转生》里的鲁迪让我决定“拿出真本事”，是清晨的跑步让我找回秩序，是 Golang 和逆向工程让我重建信心。这不是一份光鲜的成绩单，这是如何在废墟中重建自我的真实记录。</description><pubDate>Sat, 03 Jan 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;2025，这一年我很迷茫。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;曾经，我渴望拯救别人，渴望成为别人的神。&lt;/p&gt;
&lt;p&gt;后来才发现，我想拯救的，不过是当年那个在黑暗里挣扎的自己罢了。&lt;/p&gt;
&lt;p&gt;如果我足够强大，是不是就能为你拭去泪水？是不是就能擦去你经年累月的疲惫和悲伤？&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;6月底，因为在家无所事事、虚度光阴，我和家里爆发了激烈的争吵。习惯性地，我又想逃避。
那段时间，我被二次元和文字填满。4月22日注册了Bangumi，后来遇到了《&lt;a href=&quot;https://mushokutensei.jp/&quot;&gt;无职转生～到了异世界就拿出真本事～&lt;/a&gt;》。
&lt;img src=&quot;https://s2.loli.net/2026/01/03/gafsNKb5GxRrTQJ.webp&quot; alt=&quot;2025-experiences-guide-not-define-1.webp&quot; /&gt;&lt;/p&gt;
&lt;p&gt;起初，我只是想躲一躲。但没想到，这部番剧竟成了我这一年最深的心理烙印。不同于部分人眼中对“伦理崩坏”的批判，我看到的是一种近乎残酷的真实——鲁迪的前世，那个只知道打游戏、逃避现实、活得一塌糊涂的肥宅，像极了当时那个自我厌恶的我。&lt;/p&gt;
&lt;p&gt;我看着他转生，看着他决定“拿出真本事”去活。那种触动不是因为魔法或战斗，而是因为看到了一个废柴如何一点点把碎掉的自己拼凑起来。鲁迪并不完美，甚至带着许多让人诟病的恶趣味，但也正是因为这些不完美的“渣”，才让他后续为了守护家人、为了朋友挺身而出的时刻显得如此鲜活立体。&lt;/p&gt;
&lt;p&gt;我从他身上看到了“重来”的可能性。 看着他跌跌撞撞地成长，我开始问自己：如果是一个烂透了的人，是不是也有资格重新拥抱生活？&lt;/p&gt;
&lt;p&gt;那段时间，大原由衣子和LONGMAN演唱的OP/ED几乎循环在我的每一天里。音乐响起的时候，画面里鲁迪一步步踏出家门，那种即使害怕也要向前的勇气，狠狠击碎了我那层“无所谓”的伪装。它不仅仅是娱乐，更像是一面镜子，照出了我的狼狈，也照出了我心底那点未熄灭的渴望。&lt;/p&gt;
&lt;p&gt;这种心境的拉扯，在我读《人间失格》和《只要还活着》时达到了顶峰。太宰治笔下的叶藏让我看到了那个戴着面具、小心翼翼讨好世界的自己，那种“生而为人，我很抱歉”的疏离感让我共鸣；而《只要还活着》又在字里行间拽着我，配合着鲁迪重生的轨迹，提醒我即便在废墟中，生存本身依然有其重量。&lt;/p&gt;
&lt;p&gt;那是黎明前最黑的时候。被迫离开某个群聊，不得不和一些朋友告别，我的情绪跌入谷底。作为一个原本理性的人，我变得异常感性，甚至可以说是脆弱。我心底充满了负能量，我看不到未来，疯狂咒骂这个社会和时代，通过否定世界来掩盖对自己失去希望的事实。&lt;/p&gt;
&lt;p&gt;说实话，若不是缺乏那一丝决绝的勇气，或者心底仍对这个世界存有一丝留恋，我或许早已离开。&lt;/p&gt;
&lt;p&gt;家里人说得对，社会有阴暗面，但人总要向前看。即便我满腹愤懑，以我现在的能力也确实无法改变什么。或许，我的心气就是在这一次次认清现实的过程中丢失的吧。&lt;/p&gt;
&lt;p&gt;但我依然不知道路在何方。&lt;/p&gt;
&lt;p&gt;直到邻居邀请我去照顾即将上初一的小朋友。要求很简单：早起陪跑、上午预习数学、下午陪玩。本着“与其在家被念叨，不如出去赚点外快”的心态，我答应了。&lt;/p&gt;
&lt;p&gt;没想到，这成了我的救赎，也成了我“拿出真本事”的第一步。&lt;/p&gt;
&lt;p&gt;每天被迫早起虽然痛苦，但作为“老师”的责任感让我不得不支棱起来。小朋友很听话，接受能力快，这种久违的“成就感”治愈了我。清晨的奔跑让我暂时忘记了不愉快，为了不给孩子传递消极思想，我必须让自己变得阳光。这种正向反馈，让我感到了久违的轻松。&lt;/p&gt;
&lt;p&gt;状态回升后，在朋友的推荐下，我开始着手学习Golang，试图替代性能相对低下的Python。&lt;/p&gt;
&lt;p&gt;从年初给&lt;a href=&quot;https://nonebot.dev/&quot;&gt;Nonebot&lt;/a&gt;插件（answersbook, akinator等）修Bug、提Commit，到逆向&lt;a href=&quot;https://chat.akash.network/&quot;&gt;Akash Network&lt;/a&gt;的对话API。尤其是8月5日立项的 &lt;a href=&quot;https://git.006lp.cc/FuckDMCA/kuwo-api&quot;&gt;Kuwo-API&lt;/a&gt;，从最初只支持基础信息获取，到使用Jadx和IDA Pro拆解so文件找密钥，直到10月2日完成安卓端大部分接口逆向发布1.1.0版。这算是我第一个拿得出手的项目。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://s2.loli.net/2026/01/03/wOtrcse9FXb8SEy.jpg&quot; alt=&quot;2025-experiences-guide-not-define-2.jpeg&quot; /&gt;&lt;/p&gt;
&lt;p&gt;虽然拿下了一些含金量不算太高的证书，虽然还是没能找到绝对明确的目标，依然是“走一步算一步”，但我总算是走出了那段自我否定的低谷。&lt;/p&gt;
&lt;p&gt;经历了这么多，我一时语塞，只想对自己说：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;你从小到大经历了那么多苦难，直面了人性的各种阴暗与丑恶，却依然没有失去自我，没有走向极端，反而成长得更加成熟、理性与温和。&lt;/p&gt;
&lt;p&gt;你让我看到了生命的坚韧，我为你感到骄傲。这个世界本来就是这样的，你会认识形形色色的人，会遭遇无法理解的恶意，会感到失望。&lt;/p&gt;
&lt;p&gt;但只要过去了，你就会发现，其实这些经历是在提醒你——不要成为和他们一样的人。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;经历的意义在于引导你，而非定义你&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;2026，再出发吧。&lt;/p&gt;
</content:encoded></item><item><title>序</title><link>https://006lp.de/posts/preface/</link><guid isPermaLink="true">https://006lp.de/posts/preface/</guid><description>这是一篇序。</description><pubDate>Tue, 11 Nov 2025 00:00:00 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;封面来自&lt;a href=&quot;https://www.pixiv.net/artworks/136395690&quot;&gt;Pixiv @sikimosh&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;说实话，我不知道该写些什么。&lt;/p&gt;
&lt;p&gt;我承认，我的文笔很烂。&lt;br /&gt;
这几天，心总是浮着，焦虑像潮水，一波没退，另一波又来。&lt;/p&gt;
&lt;p&gt;你现在看到的这个博客，是2025年11月11日重建的第四代。&lt;/p&gt;
&lt;p&gt;从2023年12月，我第一次真正接触互联网，到2024年2月，在Serv00上搭起第一代Typecho博客，运行到夏天。后来因为装了个哪吒面板，被服务商误判为VPN/Tunnel，封了账号。我发了几次邮件申诉，石沉大海。于是9月，我用Hexo重做第二代，结果代码被我改得满屏报错，重装、重部署，三次以上，每一次都像在废墟里捡拼图。&lt;/p&gt;
&lt;p&gt;拖到2025年6月，我又换成了Astro，以为这次能稳了。结果8月，硬盘炸了。系统重装，所有源码，清零。&lt;/p&gt;
&lt;p&gt;又一次，一切归零。&lt;/p&gt;
&lt;p&gt;我拖到了11月。&lt;/p&gt;
&lt;p&gt;这一次，我不想再拖了。&lt;/p&gt;
&lt;p&gt;其实，我有很多想分享的东西。可每次坐到电脑前，敲几行字，又删掉。不是没话说，是怕说不好。我羡慕那些持续更新、文笔流畅的博主，他们像在发光。而我，总在逃避，总在等“准备好了”。&lt;/p&gt;
&lt;p&gt;现在是晚上11点。&lt;br /&gt;
我还没想好要写什么。&lt;br /&gt;
但我决定，不等了。&lt;/p&gt;
&lt;p&gt;这个博客，不完美，很粗糙，甚至有点狼狈。&lt;br /&gt;
但它是我亲手一点一点、摔了四次后，仍爬起来重建的东西。&lt;/p&gt;
&lt;p&gt;我不求它多精彩，&lt;br /&gt;
只希望它能一直活着。&lt;br /&gt;
哪怕慢一点，哪怕写得差一点。&lt;/p&gt;
&lt;p&gt;只要还在写，就还算在前进。&lt;/p&gt;
&lt;p&gt;—— 2025年11月11日，于深夜&lt;/p&gt;
</content:encoded></item></channel></rss>