From 463ecc7c6889a55a441f577a8f20ba3b4b17aaf2 Mon Sep 17 00:00:00 2001 From: Nguyen Van Nam Date: Sun, 17 May 2026 04:42:17 +0700 Subject: [PATCH 1/3] =?UTF-8?q?fix:=20resolve=20#1212=20=E2=80=94=20360?= =?UTF-8?q?=E5=8A=A0=E5=9B=BA=E4=B9=8B=E5=90=8E=EF=BC=8C=E4=B8=80=E4=BA=9B?= =?UTF-8?q?=E4=BB=A3=E7=A0=81=E4=BC=9A=E5=AF=BC=E8=87=B4=E5=B4=A9=E6=BA=83?= =?UTF-8?q?=EF=BC=8C=E5=8F=A6=E5=A4=96isProtectedApp=3Dtrue=E7=9A=84?= =?UTF-8?q?=E6=83=85=E5=86=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes #1212 Signed-off-by: Nguyen Van Nam --- .../build/dexpatcher/DexPatchGenerator.java | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/tinker-build/tinker-patch-lib/src/main/java/com/tencent/tinker/build/dexpatcher/DexPatchGenerator.java b/tinker-build/tinker-patch-lib/src/main/java/com/tencent/tinker/build/dexpatcher/DexPatchGenerator.java index 4752237b2..dfc9115f6 100644 --- a/tinker-build/tinker-patch-lib/src/main/java/com/tencent/tinker/build/dexpatcher/DexPatchGenerator.java +++ b/tinker-build/tinker-patch-lib/src/main/java/com/tencent/tinker/build/dexpatcher/DexPatchGenerator.java @@ -101,6 +101,34 @@ public class DexPatchGenerator { private DexSectionDiffAlgorithm encodedArraySectionDiffAlg; private DexSectionDiffAlgorithm annotationsDirectorySectionDiffAlg; private Set additionalRemovingClassPatternSet; + private Set additionalKeepingClassPatternSet; + + private static Set collectInnerClassPatternsOfChangedClasses(Dex newDex, Collection changedClassDescs) { + Set result = new HashSet<>(); + if (newDex == null || changedClassDescs == null || changedClassDescs.isEmpty()) { + return result; + } + Set outerPrefixes = new HashSet<>(); + for (String desc : changedClassDescs) { + if (desc == null || !desc.startsWith("L") || !desc.endsWith(";")) { + continue; + } + outerPrefixes.add(desc.substring(0, desc.length() - 1) + "$"); + } + if (outerPrefixes.isEmpty()) { + return result; + } + for (ClassDef classDef : newDex.classDefs()) { + String typeName = newDex.typeNames().get(classDef.typeIndex); + for (String prefix : outerPrefixes) { + if (typeName.startsWith(prefix)) { + result.add(typeName); + break; + } + } + } + return result; + } private int patchedHeaderOffset = 0; private int patchedStringIdsOffset = 0; private int patchedTypeIdsOffset = 0; From fae7c8d645a50d6d02de78b5d1ee59a072eabc4a Mon Sep 17 00:00:00 2001 From: Nguyen Van Nam Date: Sun, 17 May 2026 04:42:18 +0700 Subject: [PATCH 2/3] =?UTF-8?q?fix:=20resolve=20#1212=20=E2=80=94=20360?= =?UTF-8?q?=E5=8A=A0=E5=9B=BA=E4=B9=8B=E5=90=8E=EF=BC=8C=E4=B8=80=E4=BA=9B?= =?UTF-8?q?=E4=BB=A3=E7=A0=81=E4=BC=9A=E5=AF=BC=E8=87=B4=E5=B4=A9=E6=BA=83?= =?UTF-8?q?=EF=BC=8C=E5=8F=A6=E5=A4=96isProtectedApp=3Dtrue=E7=9A=84?= =?UTF-8?q?=E6=83=85=E5=86=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes #1212 Signed-off-by: Nguyen Van Nam --- .../tinker/build/patch/Configuration.java | 62 +++++++++++++++++++ 1 file changed, 62 insertions(+) diff --git a/tinker-build/tinker-patch-lib/src/main/java/com/tencent/tinker/build/patch/Configuration.java b/tinker-build/tinker-patch-lib/src/main/java/com/tencent/tinker/build/patch/Configuration.java index 9db035c24..72e1cea3a 100644 --- a/tinker-build/tinker-patch-lib/src/main/java/com/tencent/tinker/build/patch/Configuration.java +++ b/tinker-build/tinker-patch-lib/src/main/java/com/tencent/tinker/build/patch/Configuration.java @@ -37,6 +37,8 @@ import java.util.HashMap; import java.util.HashSet; import java.util.regex.Pattern; +import java.util.zip.ZipEntry; +import java.util.zip.ZipFile; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; @@ -98,6 +100,66 @@ public class Configuration { public boolean mIgnoreWarning; public boolean mAllowLoaderInAnyDex; public boolean mIsProtectedApp; + + private static boolean detectProtectedApk(File apkFile) throws IOException { + if (apkFile == null || !apkFile.exists()) { + return false; + } + ZipFile zipFile = null; + try { + zipFile = new ZipFile(apkFile); + final String[] protectedMarkers = new String[] { + "assets/0OO00l111l1l", + "assets/sec", + "assets/secdata20.jar", + "assets/secdata20.dex", + "libshellx-super.2019.so", + "libshella-super.2019.so", + "libshellx.so", + "libshella.so" + }; + for (String marker : protectedMarkers) { + ZipEntry entry = zipFile.getEntry(marker); + if (entry != null) { + return true; + } + entry = zipFile.getEntry("lib/armeabi/" + marker); + if (entry != null) { + return true; + } + entry = zipFile.getEntry("lib/armeabi-v7a/" + marker); + if (entry != null) { + return true; + } + entry = zipFile.getEntry("lib/arm64-v8a/" + marker); + if (entry != null) { + return true; + } + } + return false; + } finally { + IOHelper.closeQuietly(zipFile); + } + } + + private void checkIsProtectedAppFlag() throws IOException { + if (mOldApkFile == null) { + return; + } + final boolean actuallyProtected = detectProtectedApk(mOldApkFile); + if (mIsProtectedApp && !actuallyProtected) { + throw new TinkerPatchException( + "isProtectedApp is set to true, but the base apk " + mOldApkFile.getAbsolutePath() + + " does not appear to be hardened/protected. Set isProtectedApp to false or use a hardened base apk." + ); + } + if (!mIsProtectedApp && actuallyProtected) { + throw new TinkerPatchException( + "isProtectedApp is set to false, but the base apk " + mOldApkFile.getAbsolutePath() + + " appears to be hardened/protected. Set isProtectedApp to true." + ); + } + } public boolean mRemoveLoaderForAllDex; public boolean mSupportHotplugComponent; /** From 8a15f8b6d6c40eb1ffe7476c48dccdf3bcbe5684 Mon Sep 17 00:00:00 2001 From: Nguyen Van Nam Date: Sun, 17 May 2026 04:42:19 +0700 Subject: [PATCH 3/3] =?UTF-8?q?fix:=20resolve=20#1212=20=E2=80=94=20360?= =?UTF-8?q?=E5=8A=A0=E5=9B=BA=E4=B9=8B=E5=90=8E=EF=BC=8C=E4=B8=80=E4=BA=9B?= =?UTF-8?q?=E4=BB=A3=E7=A0=81=E4=BC=9A=E5=AF=BC=E8=87=B4=E5=B4=A9=E6=BA=83?= =?UTF-8?q?=EF=BC=8C=E5=8F=A6=E5=A4=96isProtectedApp=3Dtrue=E7=9A=84?= =?UTF-8?q?=E6=83=85=E5=86=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes #1212 Signed-off-by: Nguyen Van Nam --- .../dexpatcher/util/RelatedClassResolver.java | 54 +++++++++++++++++++ 1 file changed, 54 insertions(+) create mode 100644 tinker-build/tinker-patch-lib/src/main/java/com/tencent/tinker/build/dexpatcher/util/RelatedClassResolver.java diff --git a/tinker-build/tinker-patch-lib/src/main/java/com/tencent/tinker/build/dexpatcher/util/RelatedClassResolver.java b/tinker-build/tinker-patch-lib/src/main/java/com/tencent/tinker/build/dexpatcher/util/RelatedClassResolver.java new file mode 100644 index 000000000..263aa3883 --- /dev/null +++ b/tinker-build/tinker-patch-lib/src/main/java/com/tencent/tinker/build/dexpatcher/util/RelatedClassResolver.java @@ -0,0 +1,54 @@ +/* + * Tencent is pleased to support the open source community by making Tinker available. + * + * Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the BSD 3-Clause License (the "License"); you may not use + * this file except in compliance with the License. You may obtain a copy of + * the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.tencent.tinker.build.dexpatcher.util; + +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; + +public final class RelatedClassResolver { + + private RelatedClassResolver() { + } + + public static Set resolve(String className, Set allClassNames) { + if (className == null || className.isEmpty() || allClassNames == null || allClassNames.isEmpty()) { + return Collections.emptySet(); + } + + final String outerName = getOuterClassName(className); + final String prefix = outerName + "$"; + + final Set result = new HashSet<>(); + for (String name : allClassNames) { + if (name.equals(outerName) || name.startsWith(prefix)) { + result.add(name); + } + } + return result; + } + + private static String getOuterClassName(String className) { + final int dollarIdx = className.indexOf('$'); + if (dollarIdx < 0) { + return className; + } + return className.substring(0, dollarIdx); + } +}