Tencent/tinker · critical · TinkerRuntimeException

get public key md5 is null

Error message

get public key md5 is null

What it means

ShareSecurityCheck.init computes the MD5 of the host app's first APK signature block (PackageInfo.signatures[0]) via SharePatchFileUtil.getMD5. getMD5 returns null when the digest cannot be produced; here that null is treated as fatal and TinkerRuntimeException('get public key md5 is null') is thrown. Without the public-key md5, tinker cannot validate that patches are signed by the same key as the app.

Source

Thrown at tinker-android/tinker-android-loader-no-op/src/main/java/com/tencent/tinker/loader/shareutil/ShareSecurityCheck.java:170

                    }
                } catch (Exception e) {
                    ShareTinkerLog.e(TAG, path.getAbsolutePath(), e);
                }
            }
        }
        return false;
    }

    @SuppressLint("PackageManagerGetSignatures")
    private void init(Context context) {
        ByteArrayInputStream stream = null;
        try {
            PackageManager pm = context.getPackageManager();
            String packageName = context.getPackageName();
            PackageInfo packageInfo = pm.getPackageInfo(packageName, PackageManager.GET_SIGNATURES);
            mPublicKeyMd5 = SharePatchFileUtil.getMD5(packageInfo.signatures[0].toByteArray());
            if (mPublicKeyMd5 == null) {
                throw new TinkerRuntimeException("get public key md5 is null");
            }
        } catch (Exception e) {
            throw new TinkerRuntimeException("ShareSecurityCheck init public key fail", e);
        } finally {
            SharePatchFileUtil.closeQuietly(stream);
        }
    }
}

View on GitHub (pinned to 1b7ea02c23)

Solutions

  1. Reinstall the app normally (from Play/adb) so PackageManager returns standard signature data, then retry loading the patch.
  2. If reproducible on one device/ROM only, treat tinker as unsupported there: gate patch loading behind a device blacklist or capability check.
  3. Compute the expected md5 with the same code (SharePatchFileUtil.getMD5 on signatures[0].toByteArray()) in a debug build to see whether null is deterministic on that device.
  4. Upgrade tinker — newer builds use GET_SIGNING_CERTIFICATES paths on modern Android instead of the legacy GET_SIGNATURES flow.

Example fix

// before
mPublicKeyMd5 = SharePatchFileUtil.getMD5(packageInfo.signatures[0].toByteArray());
if (mPublicKeyMd5 == null) throw new TinkerRuntimeException("get public key md5 is null");

// after
byte[] sig = packageInfo.signatures[0].toByteArray();
mPublicKeyMd5 = SharePatchFileUtil.getMD5(sig);
if (mPublicKeyMd5 == null) {
    MessageDigest md = null;
    try { md = MessageDigest.getInstance("MD5"); } catch (NoSuchAlgorithmException ignored) { }
    mPublicKeyMd5 = (md == null) ? null : toHex(md.digest(sig));
}
Defensive patterns

Strategy: fallback

Validate before calling

Signature[] sigs = context.getPackageManager()
        .getPackageInfo(context.getPackageName(), PackageManager.GET_SIGNATURES).signatures;
if (sigs == null || sigs.length == 0 || SharePatchFileUtil.getMD5(sigs[0].toByteArray()) == null) {
    // signature identity unavailable: disable patch loading on this device
}

Try / catch

catch TinkerRuntimeException 'get public key md5 is null' -> disable tinker for the session and report the device model

Prevention

When it happens

Trigger: getMD5 failing on the signature bytes (stream/digest IO failure, though rare); packageInfo.signatures being empty on exotic ROMs so [0] is not the issue here but getMD5 receives data it cannot digest; device-level crypto provider issues.

Common situations: Devices with broken MessageDigest/MemoryFile behavior; apps installed via unusual channels (enterprise stores, some work-profile containers) where PackageManager returns atypical signature data; extremely rare vendor crypto bugs.

Related errors


AI-assisted analysis of Tencent/tinker@1b7ea02c23 (2026-08-14). Data as JSON: /api/errors/0d96df3c476f15af. Report an issue: GitHub.