33 | * optional, you can just use DefaultLoadReporter
34 | * Created by zhangshaowen on 16/4/13.
35 | */
36 | public class SampleLoadReporter extends DefaultLoadReporter {
37 | private final static String TAG = "Tinker.SampleLoadReporter";
38 |
39 | public SampleLoadReporter(Context context) {
40 | super(context);
41 | }
42 |
43 | /**
44 | * 所有的补丁合成请求都需要先通过PatchListener的检查过滤。
45 | * 这次检查不通过的回调,它运行在发起请求的进程。默认我们只是打印日志
46 | */
47 | @Override
48 | public void onLoadPatchListenerReceiveFail(final File patchFile, int errorCode) {
49 | super.onLoadPatchListenerReceiveFail(patchFile, errorCode);
50 | SampleTinkerReport.onTryApplyFail(errorCode);
51 | }
52 |
53 | /**
54 | * 这个是无论加载失败或者成功都会回调的接口。
55 | * 它返回了本次加载所用的时间、返回码等信息。
56 | * 默认我们只是简单的输出这个信息,你可以在这里加上监控上报逻辑。
57 | */
58 | @Override
59 | public void onLoadResult(File patchDirectory, int loadCode, long cost) {
60 | super.onLoadResult(patchDirectory, loadCode, cost);
61 | switch (loadCode) {
62 | case ShareConstants.ERROR_LOAD_OK:
63 | SampleTinkerReport.onLoaded(cost);
64 | break;
65 | }
66 | Looper.getMainLooper().myQueue().addIdleHandler(new MessageQueue.IdleHandler() {
67 | @Override
68 | public boolean queueIdle() {
69 | if (UpgradePatchRetry.getInstance(context).onPatchRetryLoad()) {
70 | SampleTinkerReport.onReportRetryPatch();
71 | }
72 | return false;
73 | }
74 | });
75 | }
76 |
77 | /**
78 | * 在加载过程捕捉到异常,十分希望你可以把错误信息反馈给我们。默认我们会直接卸载补丁包
79 | */
80 | @Override
81 | public void onLoadException(Throwable e, int errorCode) {
82 | super.onLoadException(e, errorCode);
83 | SampleTinkerReport.onLoadException(e, errorCode);
84 | }
85 |
86 | /**
87 | * 部分文件的md5与meta中定义的不一致。
88 | * 默认我们为了安全考虑,依然会清空补丁。
89 | */
90 | @Override
91 | public void onLoadFileMd5Mismatch(File file, int fileType) {
92 | super.onLoadFileMd5Mismatch(file, fileType);
93 | SampleTinkerReport.onLoadFileMisMatch(fileType);
94 | }
95 |
96 | /**
97 | * 在加载过程中,发现部分文件丢失的回调。
98 | * 默认若是dex,dex优化文件或者lib文件丢失,我们将尝试从补丁包去修复这些丢失的文件。
99 | * 若补丁包或者版本文件丢失,将卸载补丁包。
100 | */
101 | @Override
102 | public void onLoadFileNotFound(File file, int fileType, boolean isDirectory) {
103 | super.onLoadFileNotFound(file, fileType, isDirectory);
104 | SampleTinkerReport.onLoadFileNotFound(fileType);
105 | }
106 |
107 | /**
108 | * 加载过程补丁包的检查失败,这里可以通过错误码区分,例如签名校验失败、tinkerId不一致等原因。默认我们将会卸载补丁包
109 | */
110 | @Override
111 | public void onLoadPackageCheckFail(File patchFile, int errorCode) {
112 | super.onLoadPackageCheckFail(patchFile, errorCode);
113 | SampleTinkerReport.onLoadPackageCheckFail(errorCode);
114 | }
115 |
116 | /**
117 | * patch.info是用来管理补丁包版本的文件,这是info文件损坏的回调。
118 | * 默认我们会卸载补丁包,因为此时我们已经无法恢复了。
119 | */
120 | @Override
121 | public void onLoadPatchInfoCorrupted(String oldVersion, String newVersion, File patchInfoFile) {
122 | super.onLoadPatchInfoCorrupted(oldVersion, newVersion, patchInfoFile);
123 | SampleTinkerReport.onLoadInfoCorrupted();
124 | }
125 |
126 | /**
127 | * 系统OTA后,为了加快补丁的执行,我们会采用解释模式来执行补丁。
128 | */
129 | @Override
130 | public void onLoadInterpret(int type, Throwable e) {
131 | super.onLoadInterpret(type, e);
132 | SampleTinkerReport.onLoadInterpretReport(type, e);
133 | }
134 |
135 | /**
136 | * 补丁包版本升级的回调,只会在主进程调用。
137 | * 默认我们会杀掉其他所有的进程(保证所有进程代码的一致性),并且删掉旧版本的补丁文件。
138 | */
139 | @Override
140 | public void onLoadPatchVersionChanged(String oldVersion, String newVersion, File patchDirectoryFile, String currentPatchName) {
141 | super.onLoadPatchVersionChanged(oldVersion, newVersion, patchDirectoryFile, currentPatchName);
142 | }
143 |
144 | }
145 |
--------------------------------------------------------------------------------
/tinker-local/src/main/java/com/lqr/tinker/reporter/SamplePatchListener.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Tencent is pleased to support the open source community by making Tinker available.
3 | *
4 | * Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved.
5 | *
6 | * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except in
7 | * compliance with the License. You may obtain a copy of the License at
8 | *
9 | * https://opensource.org/licenses/BSD-3-Clause
10 | *
11 | * Unless required by applicable law or agreed to in writing, software distributed under the License is
12 | * distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
13 | * either express or implied. See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.lqr.tinker.reporter;
18 |
19 | import android.app.ActivityManager;
20 | import android.content.Context;
21 | import android.content.SharedPreferences;
22 |
23 | import com.lqr.tinker.crash.SampleUncaughtExceptionHandler;
24 | import com.lqr.tinker.utils.TinkerUtils;
25 | import com.tencent.tinker.lib.listener.DefaultPatchListener;
26 | import com.tencent.tinker.lib.util.TinkerLog;
27 | import com.tencent.tinker.loader.shareutil.ShareConstants;
28 | import com.tencent.tinker.loader.shareutil.SharePatchFileUtil;
29 | import com.tencent.tinker.loader.shareutil.ShareTinkerInternals;
30 |
31 | import java.io.File;
32 | import java.util.Properties;
33 |
34 |
35 | /**
36 | * PatchListener类是用来过滤Tinker收到的补丁包的修复、升级请求,也就是决定我们是不是真的要唤起:patch进程去尝试补丁合成。
37 | *
38 | * Created by zhangshaowen on 16/4/30.
39 | * optional, you can just use DefaultPatchListener
40 | * we can check whatever you want whether we actually send a patch request
41 | * such as we can check rom space or apk channel
42 | */
43 | public class SamplePatchListener extends DefaultPatchListener {
44 | private static final String TAG = "Tinker.SamplePatchListener";
45 |
46 | protected static final long NEW_PATCH_RESTRICTION_SPACE_SIZE_MIN = 60 * 1024 * 1024;
47 |
48 | private final int maxMemory;
49 |
50 | public SamplePatchListener(Context context) {
51 | super(context);
52 | maxMemory = ((ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE)).getMemoryClass();
53 | TinkerLog.i(TAG, "application maxMemory:" + maxMemory);
54 | }
55 |
56 | /**
57 | * 若检查成功,我们会调用TinkerPatchService.runPatchService唤起:patch进程,去尝试完成补丁合成操作。反之,会回调检验失败的接口。
58 | * 若检查失败,会在LoadReporter的onLoadPatchListenerReceiveFail中回调。
59 | *
60 | * because we use the defaultCheckPatchReceived method
61 | * the error code define by myself should after {@code ShareConstants.ERROR_RECOVER_INSERVICE
62 | *
63 | * @param path
64 | * @param newPatch
65 | * @return
66 | */
67 | @Override
68 | public int patchCheck(String path, String patchMd5) {
69 | File patchFile = new File(path);
70 | TinkerLog.i(TAG, "receive a patch file: %s, file size:%d", path, SharePatchFileUtil.getFileOrDirectorySize(patchFile));
71 | int returnCode = super.patchCheck(path, patchMd5);
72 |
73 | if (returnCode == ShareConstants.ERROR_PATCH_OK) {
74 | returnCode = TinkerUtils.checkForPatchRecover(NEW_PATCH_RESTRICTION_SPACE_SIZE_MIN, maxMemory);
75 | }
76 |
77 | if (returnCode == ShareConstants.ERROR_PATCH_OK) {
78 | SharedPreferences sp = context.getSharedPreferences(ShareConstants.TINKER_SHARE_PREFERENCE_CONFIG, Context.MODE_MULTI_PROCESS);
79 | //optional, only disable this patch file with md5
80 | int fastCrashCount = sp.getInt(patchMd5, 0);
81 | if (fastCrashCount >= SampleUncaughtExceptionHandler.MAX_CRASH_COUNT) {
82 | returnCode = TinkerUtils.ERROR_PATCH_CRASH_LIMIT;
83 | }
84 | }
85 | // Warning, it is just a sample case, you don't need to copy all of these
86 | // Interception some of the request
87 | if (returnCode == ShareConstants.ERROR_PATCH_OK) {
88 | Properties properties = ShareTinkerInternals.fastGetPatchPackageMeta(patchFile);
89 | if (properties == null) {
90 | returnCode = TinkerUtils.ERROR_PATCH_CONDITION_NOT_SATISFIED;
91 | } else {
92 | String platform = properties.getProperty(TinkerUtils.PLATFORM);
93 | TinkerLog.i(TAG, "get platform:" + platform);
94 | // check patch platform require
95 | if (platform == null || !platform.equals("all")) {
96 | returnCode = TinkerUtils.ERROR_PATCH_CONDITION_NOT_SATISFIED;
97 | }
98 | }
99 | }
100 |
101 | SampleTinkerReport.onTryApply(returnCode == ShareConstants.ERROR_PATCH_OK);
102 | return returnCode;
103 | }
104 | }
105 |
--------------------------------------------------------------------------------
/tinker-local/src/main/java/com/lqr/tinker/reporter/SamplePatchReporter.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Tencent is pleased to support the open source community by making Tinker available.
3 | *
4 | * Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved.
5 | *
6 | * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except in
7 | * compliance with the License. You may obtain a copy of the License at
8 | *
9 | * https://opensource.org/licenses/BSD-3-Clause
10 | *
11 | * Unless required by applicable law or agreed to in writing, software distributed under the License is
12 | * distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
13 | * either express or implied. See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.lqr.tinker.reporter;
18 |
19 | import android.content.Context;
20 | import android.content.Intent;
21 |
22 | import com.tencent.tinker.lib.reporter.DefaultPatchReporter;
23 | import com.tencent.tinker.loader.shareutil.SharePatchInfo;
24 |
25 | import java.io.File;
26 | import java.util.List;
27 |
28 | /**
29 | * PatchReporter类定义了Tinker在修复或者升级补丁时的一些回调
30 | *
31 | * optional, you can just use DefaultPatchReporter
32 | * Created by zhangshaowen on 16/4/8.
33 | */
34 | public class SamplePatchReporter extends DefaultPatchReporter {
35 | private final static String TAG = "Tinker.SamplePatchReporter";
36 |
37 | public SamplePatchReporter(Context context) {
38 | super(context);
39 | }
40 |
41 | /**
42 | * 这个是Patch进程启动时的回调,我们可以在这里进行一个统计的工作。
43 | */
44 | @Override
45 | public void onPatchServiceStart(Intent intent) {
46 | super.onPatchServiceStart(intent);
47 | SampleTinkerReport.onApplyPatchServiceStart();
48 | }
49 |
50 | /**
51 | * 对合成的dex文件提前进行dexopt时出现异常,默认我们会删除临时文件。
52 | */
53 | @Override
54 | public void onPatchDexOptFail(File patchFile, List dexFiles, Throwable t) {
55 | super.onPatchDexOptFail(patchFile, dexFiles, t);
56 | SampleTinkerReport.onApplyDexOptFail(t);
57 | }
58 |
59 | /**
60 | * 在补丁合成过程捕捉到异常,十分希望你可以把错误信息反馈给我们。默认我们会删除临时文件,并且将tinkerFlag设为不可用。
61 | */
62 | @Override
63 | public void onPatchException(File patchFile, Throwable e) {
64 | super.onPatchException(patchFile, e);
65 | SampleTinkerReport.onApplyCrash(e);
66 | }
67 |
68 | /**
69 | * patch.info是用来管理补丁包版本的文件,这是在更新info文件时发生损坏的回调。默认我们会卸载补丁包,因为此时我们已经无法恢复了。
70 | */
71 | @Override
72 | public void onPatchInfoCorrupted(File patchFile, String oldVersion, String newVersion) {
73 | super.onPatchInfoCorrupted(patchFile, oldVersion, newVersion);
74 | SampleTinkerReport.onApplyInfoCorrupted();
75 | }
76 |
77 | /**
78 | * 补丁合成过程对输入补丁包的检查失败,这里可以通过错误码区分,例如签名校验失败、tinkerId不一致等原因。默认我们会删除临时文件。
79 | */
80 | @Override
81 | public void onPatchPackageCheckFail(File patchFile, int errorCode) {
82 | super.onPatchPackageCheckFail(patchFile, errorCode);
83 | SampleTinkerReport.onApplyPackageCheckFail(errorCode);
84 | }
85 |
86 | /**
87 | * 这个是无论补丁合成失败或者成功都会回调的接口,它返回了本次合成的类型,时间以及结果等。
88 | * 默认我们只是简单的输出这个信息,你可以在这里加上监控上报逻辑。
89 | */
90 | @Override
91 | public void onPatchResult(File patchFile, boolean success, long cost) {
92 | super.onPatchResult(patchFile, success, cost);
93 | SampleTinkerReport.onApplied(cost, success);
94 | }
95 |
96 | /**
97 | * 从补丁包与原始安装包中合成某种类型的文件出现错误,默认我们会删除临时文件。
98 | */
99 | @Override
100 | public void onPatchTypeExtractFail(File patchFile, File extractTo, String filename, int fileType) {
101 | super.onPatchTypeExtractFail(patchFile, extractTo, filename, fileType);
102 | SampleTinkerReport.onApplyExtractFail(fileType);
103 | }
104 |
105 | /**
106 | * 对patch.info的校验版本合法性校验。若校验失败,默认我们会删除临时文件。
107 | */
108 | @Override
109 | public void onPatchVersionCheckFail(File patchFile, SharePatchInfo oldPatchInfo, String patchFileVersion) {
110 | super.onPatchVersionCheckFail(patchFile, oldPatchInfo, patchFileVersion);
111 | SampleTinkerReport.onApplyVersionCheckFail();
112 | }
113 | }
114 |
--------------------------------------------------------------------------------
/tinker-local/src/main/java/com/lqr/tinker/reporter/SampleTinkerReport.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Tencent is pleased to support the open source community by making Tinker available.
3 | *
4 | * Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved.
5 | *
6 | * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except in
7 | * compliance with the License. You may obtain a copy of the License at
8 | *
9 | * https://opensource.org/licenses/BSD-3-Clause
10 | *
11 | * Unless required by applicable law or agreed to in writing, software distributed under the License is
12 | * distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
13 | * either express or implied. See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.lqr.tinker.reporter;
18 |
19 | import com.lqr.tinker.utils.TinkerUtils;
20 | import com.tencent.tinker.lib.util.TinkerLog;
21 | import com.tencent.tinker.loader.shareutil.ShareConstants;
22 | import com.tencent.tinker.loader.shareutil.ShareTinkerInternals;
23 |
24 |
25 | /**
26 | * a simple tinker data reporter
27 | * Created by zhangshaowen on 16/9/17.
28 | */
29 | public class SampleTinkerReport {
30 | private static final String TAG = "Tinker.SampleTinkerReport";
31 |
32 | // KEY - PV
33 | public static final int KEY_REQUEST = 0;
34 | public static final int KEY_DOWNLOAD = 1;
35 | public static final int KEY_TRY_APPLY = 2;
36 | public static final int KEY_TRY_APPLY_SUCCESS = 3;
37 | public static final int KEY_APPLIED_START = 4;
38 | public static final int KEY_APPLIED = 5;
39 | public static final int KEY_LOADED = 6;
40 | public static final int KEY_CRASH_FAST_PROTECT = 7;
41 | public static final int KEY_CRASH_CAUSE_XPOSED_DALVIK = 8;
42 | public static final int KEY_CRASH_CAUSE_XPOSED_ART = 9;
43 | public static final int KEY_APPLY_WITH_RETRY = 10;
44 |
45 | //Key -- try apply detail
46 | public static final int KEY_TRY_APPLY_UPGRADE = 70;
47 | public static final int KEY_TRY_APPLY_DISABLE = 71;
48 | public static final int KEY_TRY_APPLY_RUNNING = 72;
49 | public static final int KEY_TRY_APPLY_INSERVICE = 73;
50 | public static final int KEY_TRY_APPLY_NOT_EXIST = 74;
51 | public static final int KEY_TRY_APPLY_GOOGLEPLAY = 75;
52 | public static final int KEY_TRY_APPLY_ROM_SPACE = 76;
53 | public static final int KEY_TRY_APPLY_ALREADY_APPLY = 77;
54 | public static final int KEY_TRY_APPLY_MEMORY_LIMIT = 78;
55 | public static final int KEY_TRY_APPLY_CRASH_LIMIT = 79;
56 | public static final int KEY_TRY_APPLY_CONDITION_NOT_SATISFIED = 80;
57 | public static final int KEY_TRY_APPLY_JIT = 81;
58 |
59 | //Key -- apply detail
60 | public static final int KEY_APPLIED_UPGRADE = 100;
61 | public static final int KEY_APPLIED_UPGRADE_FAIL = 101;
62 |
63 | public static final int KEY_APPLIED_EXCEPTION = 120;
64 | public static final int KEY_APPLIED_DEXOPT_OTHER = 121;
65 | public static final int KEY_APPLIED_DEXOPT_EXIST = 122;
66 | public static final int KEY_APPLIED_DEXOPT_FORMAT = 123;
67 | public static final int KEY_APPLIED_INFO_CORRUPTED = 124;
68 | //package check
69 | public static final int KEY_APPLIED_PACKAGE_CHECK_SIGNATURE = 150;
70 | public static final int KEY_APPLIED_PACKAGE_CHECK_DEX_META = 151;
71 | public static final int KEY_APPLIED_PACKAGE_CHECK_LIB_META = 152;
72 | public static final int KEY_APPLIED_PACKAGE_CHECK_APK_TINKER_ID_NOT_FOUND = 153;
73 | public static final int KEY_APPLIED_PACKAGE_CHECK_PATCH_TINKER_ID_NOT_FOUND = 154;
74 | public static final int KEY_APPLIED_PACKAGE_CHECK_META_NOT_FOUND = 155;
75 | public static final int KEY_APPLIED_PACKAGE_CHECK_TINKER_ID_NOT_EQUAL = 156;
76 | public static final int KEY_APPLIED_PACKAGE_CHECK_RES_META = 157;
77 | public static final int KEY_APPLIED_PACKAGE_CHECK_TINKERFLAG_NOT_SUPPORT = 158;
78 |
79 | //version check
80 | public static final int KEY_APPLIED_VERSION_CHECK = 180;
81 | //extract error
82 | public static final int KEY_APPLIED_PATCH_FILE_EXTRACT = 181;
83 | public static final int KEY_APPLIED_DEX_EXTRACT = 182;
84 | public static final int KEY_APPLIED_LIB_EXTRACT = 183;
85 | public static final int KEY_APPLIED_RESOURCE_EXTRACT = 184;
86 | //cost time
87 | public static final int KEY_APPLIED_SUCC_COST_5S_LESS = 200;
88 | public static final int KEY_APPLIED_SUCC_COST_10S_LESS = 201;
89 | public static final int KEY_APPLIED_SUCC_COST_30S_LESS = 202;
90 | public static final int KEY_APPLIED_SUCC_COST_60S_LESS = 203;
91 | public static final int KEY_APPLIED_SUCC_COST_OTHER = 204;
92 |
93 | public static final int KEY_APPLIED_FAIL_COST_5S_LESS = 205;
94 | public static final int KEY_APPLIED_FAIL_COST_10S_LESS = 206;
95 | public static final int KEY_APPLIED_FAIL_COST_30S_LESS = 207;
96 | public static final int KEY_APPLIED_FAIL_COST_60S_LESS = 208;
97 | public static final int KEY_APPLIED_FAIL_COST_OTHER = 209;
98 |
99 |
100 | // KEY -- load detail
101 | public static final int KEY_LOADED_UNKNOWN_EXCEPTION = 250;
102 | public static final int KEY_LOADED_UNCAUGHT_EXCEPTION = 251;
103 | public static final int KEY_LOADED_EXCEPTION_DEX = 252;
104 | public static final int KEY_LOADED_EXCEPTION_DEX_CHECK = 253;
105 | public static final int KEY_LOADED_EXCEPTION_RESOURCE = 254;
106 | public static final int KEY_LOADED_EXCEPTION_RESOURCE_CHECK = 255;
107 |
108 |
109 | public static final int KEY_LOADED_MISMATCH_DEX = 300;
110 | public static final int KEY_LOADED_MISMATCH_LIB = 301;
111 | public static final int KEY_LOADED_MISMATCH_RESOURCE = 302;
112 | public static final int KEY_LOADED_MISSING_DEX = 303;
113 | public static final int KEY_LOADED_MISSING_LIB = 304;
114 | public static final int KEY_LOADED_MISSING_PATCH_FILE = 305;
115 | public static final int KEY_LOADED_MISSING_PATCH_INFO = 306;
116 | public static final int KEY_LOADED_MISSING_DEX_OPT = 307;
117 | public static final int KEY_LOADED_MISSING_RES = 308;
118 | public static final int KEY_LOADED_INFO_CORRUPTED = 309;
119 |
120 | //load package check
121 | public static final int KEY_LOADED_PACKAGE_CHECK_SIGNATURE = 350;
122 | public static final int KEY_LOADED_PACKAGE_CHECK_DEX_META = 351;
123 | public static final int KEY_LOADED_PACKAGE_CHECK_LIB_META = 352;
124 | public static final int KEY_LOADED_PACKAGE_CHECK_APK_TINKER_ID_NOT_FOUND = 353;
125 | public static final int KEY_LOADED_PACKAGE_CHECK_PATCH_TINKER_ID_NOT_FOUND = 354;
126 | public static final int KEY_LOADED_PACKAGE_CHECK_TINKER_ID_NOT_EQUAL = 355;
127 | public static final int KEY_LOADED_PACKAGE_CHECK_PACKAGE_META_NOT_FOUND = 356;
128 | public static final int KEY_LOADED_PACKAGE_CHECK_RES_META = 357;
129 | public static final int KEY_LOADED_PACKAGE_CHECK_TINKERFLAG_NOT_SUPPORT = 358;
130 |
131 |
132 | public static final int KEY_LOADED_SUCC_COST_500_LESS = 400;
133 | public static final int KEY_LOADED_SUCC_COST_1000_LESS = 401;
134 | public static final int KEY_LOADED_SUCC_COST_3000_LESS = 402;
135 | public static final int KEY_LOADED_SUCC_COST_5000_LESS = 403;
136 | public static final int KEY_LOADED_SUCC_COST_OTHER = 404;
137 |
138 | public static final int KEY_LOADED_INTERPRET_GET_INSTRUCTION_SET_ERROR = 450;
139 | public static final int KEY_LOADED_INTERPRET_INTERPRET_COMMAND_ERROR = 451;
140 | public static final int KEY_LOADED_INTERPRET_TYPE_INTERPRET_OK = 452;
141 |
142 |
143 | interface Reporter {
144 | void onReport(int key);
145 |
146 | void onReport(String message);
147 | }
148 |
149 | private static Reporter reporter = null;
150 |
151 | public void setReporter(Reporter reporter) {
152 | this.reporter = reporter;
153 | }
154 |
155 | public static void onTryApply(boolean success) {
156 | if (reporter == null) {
157 | return;
158 | }
159 | reporter.onReport(KEY_TRY_APPLY);
160 |
161 | reporter.onReport(KEY_TRY_APPLY_UPGRADE);
162 |
163 | if (success) {
164 | reporter.onReport(KEY_TRY_APPLY_SUCCESS);
165 | }
166 | }
167 |
168 | public static void onTryApplyFail(int errorCode) {
169 | if (reporter == null) {
170 | return;
171 | }
172 | switch (errorCode) {
173 | case ShareConstants.ERROR_PATCH_NOTEXIST: // 当前tinkerFlag为不可用状态。(-1)
174 | reporter.onReport(KEY_TRY_APPLY_NOT_EXIST);
175 | break;
176 | case ShareConstants.ERROR_PATCH_DISABLE:// 输入的临时补丁包文件不存在。(-2)
177 | reporter.onReport(KEY_TRY_APPLY_DISABLE);
178 | break;
179 | case ShareConstants.ERROR_PATCH_INSERVICE:// 不能在:patch补丁合成进程,发起补丁的合成请求。(-4)
180 | reporter.onReport(KEY_TRY_APPLY_INSERVICE);
181 | break;
182 | case ShareConstants.ERROR_PATCH_RUNNING:// 当前:patch补丁合成进程正在运行。(-3)
183 | reporter.onReport(KEY_TRY_APPLY_RUNNING);
184 | break;
185 | case ShareConstants.ERROR_PATCH_JIT:// 补丁不支持 N 之前的 JIT 模式。(-5)
186 | reporter.onReport(KEY_TRY_APPLY_JIT);
187 | break;
188 | case TinkerUtils.ERROR_PATCH_ROM_SPACE:// 没有足够的空间(-21)
189 | reporter.onReport(KEY_TRY_APPLY_ROM_SPACE);
190 | break;
191 | case TinkerUtils.ERROR_PATCH_GOOGLEPLAY_CHANNEL:// GP渠道(-20)
192 | reporter.onReport(KEY_TRY_APPLY_GOOGLEPLAY);
193 | break;
194 | case ShareConstants.ERROR_PATCH_ALREADY_APPLY:// 补丁已经应用。(-6)
195 | reporter.onReport(KEY_TRY_APPLY_ALREADY_APPLY);
196 | break;
197 | case TinkerUtils.ERROR_PATCH_CRASH_LIMIT:// 崩溃界限(-23)
198 | reporter.onReport(KEY_TRY_APPLY_CRASH_LIMIT);
199 | break;
200 | case TinkerUtils.ERROR_PATCH_MEMORY_LIMIT:// 最大内存(-22)
201 | reporter.onReport(KEY_TRY_APPLY_MEMORY_LIMIT);
202 | break;
203 | case TinkerUtils.ERROR_PATCH_CONDITION_NOT_SATISFIED:// 条件不满意(-24)
204 | reporter.onReport(KEY_TRY_APPLY_CONDITION_NOT_SATISFIED);
205 | break;
206 |
207 | }
208 | }
209 |
210 | public static void onLoadPackageCheckFail(int errorCode) {
211 | if (reporter == null) {
212 | return;
213 | }
214 | switch (errorCode) {
215 | case ShareConstants.ERROR_PACKAGE_CHECK_SIGNATURE_FAIL:
216 | reporter.onReport(KEY_LOADED_PACKAGE_CHECK_SIGNATURE);
217 | break;
218 | case ShareConstants.ERROR_PACKAGE_CHECK_DEX_META_CORRUPTED:
219 | reporter.onReport(KEY_LOADED_PACKAGE_CHECK_DEX_META);
220 | break;
221 | case ShareConstants.ERROR_PACKAGE_CHECK_LIB_META_CORRUPTED:
222 | reporter.onReport(KEY_LOADED_PACKAGE_CHECK_LIB_META);
223 | break;
224 | case ShareConstants.ERROR_PACKAGE_CHECK_PATCH_TINKER_ID_NOT_FOUND:
225 | reporter.onReport(KEY_LOADED_PACKAGE_CHECK_PATCH_TINKER_ID_NOT_FOUND);
226 | break;
227 | case ShareConstants.ERROR_PACKAGE_CHECK_APK_TINKER_ID_NOT_FOUND:
228 | reporter.onReport(KEY_LOADED_PACKAGE_CHECK_APK_TINKER_ID_NOT_FOUND);
229 | break;
230 | case ShareConstants.ERROR_PACKAGE_CHECK_TINKER_ID_NOT_EQUAL:
231 | reporter.onReport(KEY_LOADED_PACKAGE_CHECK_TINKER_ID_NOT_EQUAL);
232 |
233 | break;
234 | case ShareConstants.ERROR_PACKAGE_CHECK_PACKAGE_META_NOT_FOUND:
235 | reporter.onReport(KEY_LOADED_PACKAGE_CHECK_PACKAGE_META_NOT_FOUND);
236 | break;
237 | case ShareConstants.ERROR_PACKAGE_CHECK_RESOURCE_META_CORRUPTED:
238 | reporter.onReport(KEY_LOADED_PACKAGE_CHECK_RES_META);
239 | break;
240 | case ShareConstants.ERROR_PACKAGE_CHECK_TINKERFLAG_NOT_SUPPORT:
241 | reporter.onReport(KEY_LOADED_PACKAGE_CHECK_TINKERFLAG_NOT_SUPPORT);
242 | break;
243 | }
244 | }
245 |
246 | public static void onLoaded(long cost) {
247 | if (reporter == null) {
248 | return;
249 | }
250 | reporter.onReport(KEY_LOADED);
251 |
252 | if (cost < 0L) {
253 | TinkerLog.e(TAG, "hp_report report load cost failed, invalid cost");
254 | return;
255 | }
256 |
257 | if (cost <= 500) {
258 | reporter.onReport(KEY_LOADED_SUCC_COST_500_LESS);
259 | } else if (cost <= 1000) {
260 | reporter.onReport(KEY_LOADED_SUCC_COST_1000_LESS);
261 | } else if (cost <= 3000) {
262 | reporter.onReport(KEY_LOADED_SUCC_COST_3000_LESS);
263 | } else if (cost <= 5000) {
264 | reporter.onReport(KEY_LOADED_SUCC_COST_5000_LESS);
265 | } else {
266 | reporter.onReport(KEY_LOADED_SUCC_COST_OTHER);
267 | }
268 | }
269 |
270 | public static void onLoadInfoCorrupted() {
271 | if (reporter == null) {
272 | return;
273 | }
274 | reporter.onReport(KEY_LOADED_INFO_CORRUPTED);
275 | }
276 |
277 | public static void onLoadFileNotFound(int fileType) {
278 | if (reporter == null) {
279 | return;
280 | }
281 | switch (fileType) {
282 | case ShareConstants.TYPE_DEX_OPT:
283 | reporter.onReport(KEY_LOADED_MISSING_DEX_OPT);
284 | break;
285 | case ShareConstants.TYPE_DEX:
286 | reporter.onReport(KEY_LOADED_MISSING_DEX);
287 | break;
288 | case ShareConstants.TYPE_LIBRARY:
289 | reporter.onReport(KEY_LOADED_MISSING_LIB);
290 | break;
291 | case ShareConstants.TYPE_PATCH_FILE:
292 | reporter.onReport(KEY_LOADED_MISSING_PATCH_FILE);
293 | break;
294 | case ShareConstants.TYPE_PATCH_INFO:
295 | reporter.onReport(KEY_LOADED_MISSING_PATCH_INFO);
296 | break;
297 | case ShareConstants.TYPE_RESOURCE:
298 | reporter.onReport(KEY_LOADED_MISSING_RES);
299 | break;
300 | }
301 | }
302 |
303 | public static void onLoadInterpretReport(int type, Throwable e) {
304 | if (reporter == null) {
305 | return;
306 | }
307 | switch (type) {
308 | case ShareConstants.TYPE_INTERPRET_GET_INSTRUCTION_SET_ERROR:
309 | reporter.onReport(KEY_LOADED_INTERPRET_GET_INSTRUCTION_SET_ERROR);
310 | reporter.onReport("Tinker Exception:interpret occur exception " + TinkerUtils.getExceptionCauseString(e));
311 | break;
312 | case ShareConstants.TYPE_INTERPRET_COMMAND_ERROR:
313 | reporter.onReport(KEY_LOADED_INTERPRET_INTERPRET_COMMAND_ERROR);
314 | reporter.onReport("Tinker Exception:interpret occur exception " + TinkerUtils.getExceptionCauseString(e));
315 | break;
316 | case ShareConstants.TYPE_INTERPRET_OK:
317 | reporter.onReport(KEY_LOADED_INTERPRET_TYPE_INTERPRET_OK);
318 | break;
319 | }
320 | }
321 |
322 | public static void onLoadFileMisMatch(int fileType) {
323 | if (reporter == null) {
324 | return;
325 | }
326 | switch (fileType) {
327 | case ShareConstants.TYPE_DEX:
328 | reporter.onReport(KEY_LOADED_MISMATCH_DEX);
329 | break;
330 | case ShareConstants.TYPE_LIBRARY:
331 | reporter.onReport(KEY_LOADED_MISMATCH_LIB);
332 | break;
333 | case ShareConstants.TYPE_RESOURCE:
334 | reporter.onReport(KEY_LOADED_MISMATCH_RESOURCE);
335 | break;
336 | }
337 | }
338 |
339 | public static void onLoadException(Throwable throwable, int errorCode) {
340 | if (reporter == null) {
341 | return;
342 | }
343 | boolean isCheckFail = false;
344 | switch (errorCode) {
345 | case ShareConstants.ERROR_LOAD_EXCEPTION_DEX:
346 | if (throwable.getMessage().contains(ShareConstants.CHECK_DEX_INSTALL_FAIL)) {
347 | reporter.onReport(KEY_LOADED_EXCEPTION_DEX_CHECK);
348 | isCheckFail = true;
349 | TinkerLog.e(TAG, "tinker dex check fail:" + throwable.getMessage());
350 | } else {
351 | reporter.onReport(KEY_LOADED_EXCEPTION_DEX);
352 | TinkerLog.e(TAG, "tinker dex reflect fail:" + throwable.getMessage());
353 | }
354 | break;
355 | case ShareConstants.ERROR_LOAD_EXCEPTION_RESOURCE:
356 | if (throwable.getMessage().contains(ShareConstants.CHECK_RES_INSTALL_FAIL)) {
357 | reporter.onReport(KEY_LOADED_EXCEPTION_RESOURCE_CHECK);
358 | isCheckFail = true;
359 | TinkerLog.e(TAG, "tinker res check fail:" + throwable.getMessage());
360 | } else {
361 | reporter.onReport(KEY_LOADED_EXCEPTION_RESOURCE);
362 | TinkerLog.e(TAG, "tinker res reflect fail:" + throwable.getMessage());
363 | }
364 | break;
365 | case ShareConstants.ERROR_LOAD_EXCEPTION_UNCAUGHT:
366 | reporter.onReport(KEY_LOADED_UNCAUGHT_EXCEPTION);
367 | break;
368 | case ShareConstants.ERROR_LOAD_EXCEPTION_UNKNOWN:
369 | reporter.onReport(KEY_LOADED_UNKNOWN_EXCEPTION);
370 | break;
371 | }
372 | //reporter exception, for dex check fail, we don't need to report stacktrace
373 | if (!isCheckFail) {
374 | reporter.onReport("Tinker Exception:load tinker occur exception " + TinkerUtils.getExceptionCauseString(throwable));
375 | }
376 | }
377 |
378 | public static void onApplyPatchServiceStart() {
379 | if (reporter == null) {
380 | return;
381 | }
382 | reporter.onReport(KEY_APPLIED_START);
383 | }
384 |
385 | public static void onApplyDexOptFail(Throwable throwable) {
386 | if (reporter == null) {
387 | return;
388 | }
389 | if (throwable.getMessage().contains(ShareConstants.CHECK_DEX_OAT_EXIST_FAIL)) {
390 | reporter.onReport(KEY_APPLIED_DEXOPT_EXIST);
391 | } else if (throwable.getMessage().contains(ShareConstants.CHECK_DEX_OAT_FORMAT_FAIL)) {
392 | reporter.onReport(KEY_APPLIED_DEXOPT_FORMAT);
393 | } else {
394 | reporter.onReport(KEY_APPLIED_DEXOPT_OTHER);
395 | reporter.onReport("Tinker Exception:apply tinker occur exception " + TinkerUtils.getExceptionCauseString(throwable));
396 | }
397 | }
398 |
399 | public static void onApplyInfoCorrupted() {
400 | if (reporter == null) {
401 | return;
402 | }
403 | reporter.onReport(KEY_APPLIED_INFO_CORRUPTED);
404 | }
405 |
406 | public static void onApplyVersionCheckFail() {
407 | if (reporter == null) {
408 | return;
409 | }
410 | reporter.onReport(KEY_APPLIED_VERSION_CHECK);
411 | }
412 |
413 | public static void onApplyExtractFail(int fileType) {
414 | if (reporter == null) {
415 | return;
416 | }
417 | switch (fileType) {
418 | case ShareConstants.TYPE_DEX:
419 | reporter.onReport(KEY_APPLIED_DEX_EXTRACT);
420 | break;
421 | case ShareConstants.TYPE_LIBRARY:
422 | reporter.onReport(KEY_APPLIED_LIB_EXTRACT);
423 | break;
424 | case ShareConstants.TYPE_PATCH_FILE:
425 | reporter.onReport(KEY_APPLIED_PATCH_FILE_EXTRACT);
426 | break;
427 | case ShareConstants.TYPE_RESOURCE:
428 | reporter.onReport(KEY_APPLIED_RESOURCE_EXTRACT);
429 | break;
430 | }
431 | }
432 |
433 | public static void onApplied(long cost, boolean success) {
434 | if (reporter == null) {
435 | return;
436 | }
437 | if (success) {
438 | reporter.onReport(KEY_APPLIED);
439 | }
440 |
441 | if (success) {
442 | reporter.onReport(KEY_APPLIED_UPGRADE);
443 | } else {
444 | reporter.onReport(KEY_APPLIED_UPGRADE_FAIL);
445 | }
446 |
447 | TinkerLog.i(TAG, "hp_report report apply cost = %d", cost);
448 |
449 | if (cost < 0L) {
450 | TinkerLog.e(TAG, "hp_report report apply cost failed, invalid cost");
451 | return;
452 | }
453 |
454 | if (cost <= 5000) {
455 | if (success) {
456 | reporter.onReport(KEY_APPLIED_SUCC_COST_5S_LESS);
457 | } else {
458 | reporter.onReport(KEY_APPLIED_FAIL_COST_5S_LESS);
459 | }
460 | } else if (cost <= 10 * 1000) {
461 | if (success) {
462 | reporter.onReport(KEY_APPLIED_SUCC_COST_10S_LESS);
463 | } else {
464 | reporter.onReport(KEY_APPLIED_FAIL_COST_10S_LESS);
465 | }
466 | } else if (cost <= 30 * 1000) {
467 | if (success) {
468 | reporter.onReport(KEY_APPLIED_SUCC_COST_30S_LESS);
469 | } else {
470 | reporter.onReport(KEY_APPLIED_FAIL_COST_30S_LESS);
471 | }
472 | } else if (cost <= 60 * 1000) {
473 | if (success) {
474 | reporter.onReport(KEY_APPLIED_SUCC_COST_60S_LESS);
475 | } else {
476 | reporter.onReport(KEY_APPLIED_FAIL_COST_60S_LESS);
477 | }
478 | } else {
479 | if (success) {
480 | reporter.onReport(KEY_APPLIED_SUCC_COST_OTHER);
481 | } else {
482 | reporter.onReport(KEY_APPLIED_FAIL_COST_OTHER);
483 | }
484 | }
485 | }
486 |
487 | public static void onApplyPackageCheckFail(int errorCode) {
488 | if (reporter == null) {
489 | return;
490 | }
491 | TinkerLog.i(TAG, "hp_report package check failed, error = %d", errorCode);
492 |
493 | switch (errorCode) {
494 | case ShareConstants.ERROR_PACKAGE_CHECK_SIGNATURE_FAIL:
495 | reporter.onReport(KEY_APPLIED_PACKAGE_CHECK_SIGNATURE);
496 | break;
497 | case ShareConstants.ERROR_PACKAGE_CHECK_DEX_META_CORRUPTED:
498 | reporter.onReport(KEY_APPLIED_PACKAGE_CHECK_DEX_META);
499 | break;
500 | case ShareConstants.ERROR_PACKAGE_CHECK_LIB_META_CORRUPTED:
501 | reporter.onReport(KEY_APPLIED_PACKAGE_CHECK_LIB_META);
502 | break;
503 | case ShareConstants.ERROR_PACKAGE_CHECK_PATCH_TINKER_ID_NOT_FOUND:
504 | reporter.onReport(KEY_APPLIED_PACKAGE_CHECK_PATCH_TINKER_ID_NOT_FOUND);
505 | break;
506 | case ShareConstants.ERROR_PACKAGE_CHECK_APK_TINKER_ID_NOT_FOUND:
507 | reporter.onReport(KEY_APPLIED_PACKAGE_CHECK_APK_TINKER_ID_NOT_FOUND);
508 | break;
509 | case ShareConstants.ERROR_PACKAGE_CHECK_TINKER_ID_NOT_EQUAL:
510 | reporter.onReport(KEY_APPLIED_PACKAGE_CHECK_TINKER_ID_NOT_EQUAL);
511 | break;
512 | case ShareConstants.ERROR_PACKAGE_CHECK_PACKAGE_META_NOT_FOUND:
513 | reporter.onReport(KEY_APPLIED_PACKAGE_CHECK_META_NOT_FOUND);
514 | break;
515 | case ShareConstants.ERROR_PACKAGE_CHECK_RESOURCE_META_CORRUPTED:
516 | reporter.onReport(KEY_APPLIED_PACKAGE_CHECK_RES_META);
517 | break;
518 | case ShareConstants.ERROR_PACKAGE_CHECK_TINKERFLAG_NOT_SUPPORT:
519 | reporter.onReport(KEY_APPLIED_PACKAGE_CHECK_TINKERFLAG_NOT_SUPPORT);
520 | break;
521 | }
522 | }
523 |
524 | public static void onApplyCrash(Throwable throwable) {
525 | if (reporter == null) {
526 | return;
527 | }
528 | reporter.onReport(KEY_APPLIED_EXCEPTION);
529 | reporter.onReport("Tinker Exception:apply tinker occur exception " + TinkerUtils.getExceptionCauseString(throwable));
530 | }
531 |
532 | public static void onFastCrashProtect() {
533 | if (reporter == null) {
534 | return;
535 | }
536 | reporter.onReport(KEY_CRASH_FAST_PROTECT);
537 | }
538 |
539 | public static void onXposedCrash() {
540 | if (reporter == null) {
541 | return;
542 | }
543 | if (ShareTinkerInternals.isVmArt()) {
544 | reporter.onReport(KEY_CRASH_CAUSE_XPOSED_ART);
545 | } else {
546 | reporter.onReport(KEY_CRASH_CAUSE_XPOSED_DALVIK);
547 | }
548 | }
549 |
550 | public static void onReportRetryPatch() {
551 | if (reporter == null) {
552 | return;
553 | }
554 | reporter.onReport(KEY_APPLY_WITH_RETRY);
555 | }
556 |
557 | }
558 |
--------------------------------------------------------------------------------
/tinker-local/src/main/java/com/lqr/tinker/service/SampleResultService.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Tencent is pleased to support the open source community by making Tinker available.
3 | *
4 | * Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved.
5 | *
6 | * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except in
7 | * compliance with the License. You may obtain a copy of the License at
8 | *
9 | * https://opensource.org/licenses/BSD-3-Clause
10 | *
11 | * Unless required by applicable law or agreed to in writing, software distributed under the License is
12 | * distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
13 | * either express or implied. See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.lqr.tinker.service;
18 |
19 | import android.os.Handler;
20 | import android.os.Looper;
21 | import android.widget.Toast;
22 |
23 | import com.lqr.tinker.utils.TinkerUtils;
24 | import com.tencent.tinker.lib.service.DefaultTinkerResultService;
25 | import com.tencent.tinker.lib.service.PatchResult;
26 | import com.tencent.tinker.lib.util.TinkerLog;
27 | import com.tencent.tinker.lib.util.TinkerServiceInternals;
28 |
29 | import java.io.File;
30 |
31 |
32 | /**
33 | * AbstractResultService类是:patch补丁合成进程将合成结果返回给主进程的类。
34 | * 需要在AndroidManifest上添加你的Service。
35 | *
36 | * optional, you can just use DefaultTinkerResultService
37 | * we can restart process when we are at background or screen off
38 | * Created by zhangshaowen on 16/4/13.
39 | */
40 | public class SampleResultService extends DefaultTinkerResultService {
41 | private static final String TAG = "Tinker.SampleResultService";
42 |
43 | @Override
44 | public void onPatchResult(final PatchResult result) {
45 | if (result == null) {
46 | TinkerLog.e(TAG, "SampleResultService received null result!!!!");
47 | return;
48 | }
49 | TinkerLog.i(TAG, "SampleResultService receive result: %s", result.toString());
50 |
51 | //first, we want to kill the recover process
52 | TinkerServiceInternals.killTinkerPatchServiceProcess(getApplicationContext());
53 |
54 | Handler handler = new Handler(Looper.getMainLooper());
55 | handler.post(new Runnable() {
56 | @Override
57 | public void run() {
58 | if (result.isSuccess) {
59 | Toast.makeText(getApplicationContext(), "patch success, please restart process", Toast.LENGTH_LONG).show();
60 | } else {
61 | Toast.makeText(getApplicationContext(), "patch fail, please check reason", Toast.LENGTH_LONG).show();
62 | }
63 | }
64 | });
65 | // is success and newPatch, it is nice to delete the raw file, and restart at once
66 | // for old patch, you can't delete the patch file
67 | if (result.isSuccess) {
68 | deleteRawPatchFile(new File(result.rawPatchFilePath));
69 |
70 | //not like TinkerResultService, I want to restart just when I am at background!
71 | //if you have not install tinker this moment, you can use TinkerApplicationHelper api
72 | if (checkIfNeedKill(result)) {
73 | if (TinkerUtils.isBackground()) {
74 | TinkerLog.i(TAG, "it is in background, just restart process");
75 | restartProcess();
76 | } else {
77 | //we can wait process at background, such as onAppBackground
78 | //or we can restart when the screen off
79 | TinkerLog.i(TAG, "tinker wait screen to restart process");
80 | new TinkerUtils.ScreenState(getApplicationContext(), new TinkerUtils.ScreenState.IOnScreenOff() {
81 | @Override
82 | public void onScreenOff() {
83 | restartProcess();
84 | }
85 | });
86 | }
87 | } else {
88 | TinkerLog.i(TAG, "I have already install the newly patch version!");
89 | }
90 | }
91 | }
92 |
93 | /**
94 | * you can restart your process through service or broadcast
95 | */
96 | private void restartProcess() {
97 | TinkerLog.i(TAG, "app is background now, i can kill quietly");
98 | //you can send service or broadcast intent to restart your process
99 | android.os.Process.killProcess(android.os.Process.myPid());
100 | }
101 |
102 | }
103 |
--------------------------------------------------------------------------------
/tinker-local/src/main/java/com/lqr/tinker/utils/TinkerManager.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Tencent is pleased to support the open source community by making Tinker available.
3 | *
4 | * Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved.
5 | *
6 | * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except in
7 | * compliance with the License. You may obtain a copy of the License at
8 | *
9 | * https://opensource.org/licenses/BSD-3-Clause
10 | *
11 | * Unless required by applicable law or agreed to in writing, software distributed under the License is
12 | * distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
13 | * either express or implied. See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.lqr.tinker.utils;
18 |
19 | import com.lqr.tinker.crash.SampleUncaughtExceptionHandler;
20 | import com.lqr.tinker.reporter.SampleLoadReporter;
21 | import com.lqr.tinker.reporter.SamplePatchListener;
22 | import com.lqr.tinker.reporter.SamplePatchReporter;
23 | import com.lqr.tinker.service.SampleResultService;
24 | import com.tencent.tinker.lib.listener.PatchListener;
25 | import com.tencent.tinker.lib.patch.AbstractPatch;
26 | import com.tencent.tinker.lib.patch.UpgradePatch;
27 | import com.tencent.tinker.lib.reporter.LoadReporter;
28 | import com.tencent.tinker.lib.reporter.PatchReporter;
29 | import com.tencent.tinker.lib.tinker.TinkerInstaller;
30 | import com.tencent.tinker.lib.util.TinkerLog;
31 | import com.tencent.tinker.lib.util.UpgradePatchRetry;
32 | import com.tencent.tinker.loader.app.ApplicationLike;
33 |
34 |
35 | /**
36 | * Created by zhangshaowen on 16/7/3.
37 | */
38 | public class TinkerManager {
39 | private static final String TAG = "Tinker.TinkerManager";
40 |
41 | private static ApplicationLike applicationLike;
42 | private static SampleUncaughtExceptionHandler uncaughtExceptionHandler;
43 | private static boolean isInstalled = false;
44 |
45 | public static void setTinkerApplicationLike(ApplicationLike appLike) {
46 | applicationLike = appLike;
47 | }
48 |
49 | public static ApplicationLike getTinkerApplicationLike() {
50 | return applicationLike;
51 | }
52 |
53 | /**
54 | * 初始化全局异常捕获
55 | */
56 | public static void initFastCrashProtect() {
57 | if (uncaughtExceptionHandler == null) {
58 | uncaughtExceptionHandler = new SampleUncaughtExceptionHandler();
59 | Thread.setDefaultUncaughtExceptionHandler(uncaughtExceptionHandler);
60 | }
61 | }
62 |
63 | /**
64 | * 开启或关闭补丁升级重试功能
65 | */
66 | public static void setUpgradeRetryEnable(boolean enable) {
67 | UpgradePatchRetry.getInstance(applicationLike.getApplication()).setRetryEnable(enable);
68 | }
69 |
70 |
71 | /**
72 | * 默认安装Tinker(使用默认的reporter类:DefaultLoadReporter、DefaultPatchReporter、DefaultPatchListener、DefaultTinkerResultService)
73 | * 如果你不需要对监听app打补丁的情况(如:当打补丁失败时上传失败信息),则使用该方法
74 | */
75 | public static void sampleInstallTinker(ApplicationLike appLike) {
76 | if (isInstalled) {
77 | TinkerLog.w(TAG, "install tinker, but has installed, ignore");
78 | return;
79 | }
80 | TinkerInstaller.install(appLike);
81 | isInstalled = true;
82 |
83 | }
84 |
85 | /**
86 | * 自定义安装Tinker(使用你自定义的reporter类:SampleLoadReporter、SamplePatchReporter、SamplePatchListener、SampleResultService)
87 | * you can specify all class you want.
88 | * sometimes, you can only install tinker in some process you want!
89 | */
90 | public static void installTinker(ApplicationLike appLike) {
91 | if (isInstalled) {
92 | TinkerLog.w(TAG, "install tinker, but has installed, ignore");
93 | return;
94 | }
95 | //or you can just use DefaultLoadReporter
96 | LoadReporter loadReporter = new SampleLoadReporter(appLike.getApplication());
97 | //or you can just use DefaultPatchReporter
98 | PatchReporter patchReporter = new SamplePatchReporter(appLike.getApplication());
99 | //or you can just use DefaultPatchListener
100 | PatchListener patchListener = new SamplePatchListener(appLike.getApplication());
101 | //you can set your own upgrade patch if you need
102 | AbstractPatch upgradePatchProcessor = new UpgradePatch();
103 |
104 | TinkerInstaller.install(appLike,
105 | loadReporter, patchReporter, patchListener,
106 | SampleResultService.class, upgradePatchProcessor);
107 |
108 | isInstalled = true;
109 | }
110 | }
111 |
--------------------------------------------------------------------------------
/tinker-local/src/main/java/com/lqr/tinker/utils/TinkerUtils.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Tencent is pleased to support the open source community by making Tinker available.
3 | *
4 | * Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved.
5 | *
6 | * Licensed under the BSD 3-Clause License (the "License"); you may not use this file except in
7 | * compliance with the License. You may obtain a copy of the License at
8 | *
9 | * https://opensource.org/licenses/BSD-3-Clause
10 | *
11 | * Unless required by applicable law or agreed to in writing, software distributed under the License is
12 | * distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
13 | * either express or implied. See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.lqr.tinker.utils;
18 |
19 | import android.content.BroadcastReceiver;
20 | import android.content.Context;
21 | import android.content.Intent;
22 | import android.content.IntentFilter;
23 | import android.os.Environment;
24 | import android.os.StatFs;
25 |
26 | import com.tencent.tinker.lib.util.TinkerLog;
27 | import com.tencent.tinker.loader.shareutil.ShareConstants;
28 |
29 | import java.io.ByteArrayOutputStream;
30 | import java.io.File;
31 | import java.io.IOException;
32 | import java.io.PrintStream;
33 |
34 | /**
35 | * Created by zhangshaowen on 16/4/7.
36 | */
37 | public class TinkerUtils {
38 | private static final String TAG = "Tinker.Utils";
39 |
40 | /**
41 | * the error code define by myself
42 | * should after {@code ShareConstants.ERROR_PATCH_INSERVICE
43 | */
44 | public static final int ERROR_PATCH_GOOGLEPLAY_CHANNEL = -20;// GooglePlay渠道不允许使用热修复
45 | public static final int ERROR_PATCH_ROM_SPACE = -21;// 没有足够的空间
46 | public static final int ERROR_PATCH_MEMORY_LIMIT = -22;// 最大内存
47 | public static final int ERROR_PATCH_CRASH_LIMIT = -23;// 崩溃界限
48 | public static final int ERROR_PATCH_CONDITION_NOT_SATISFIED = -24;// 条件不满意
49 |
50 | public static final String PLATFORM = "platform";
51 |
52 | public static final int MIN_MEMORY_HEAP_SIZE = 45;
53 |
54 | private static boolean background = false;
55 |
56 | /**
57 | * 判断是否是GP渠道
58 | */
59 | public static boolean isGooglePlay() {
60 | return false;
61 | }
62 |
63 | /**
64 | * 判断当前App是否处于后台
65 | */
66 | public static boolean isBackground() {
67 | return background;
68 | }
69 |
70 | public static void setBackground(boolean back) {
71 | background = back;
72 | }
73 |
74 | /**
75 | * 判断当前是否非GP渠道,且空间足够
76 | */
77 | public static int checkForPatchRecover(long roomSize, int maxMemory) {
78 | if (TinkerUtils.isGooglePlay()) {
79 | return TinkerUtils.ERROR_PATCH_GOOGLEPLAY_CHANNEL;
80 | }
81 | if (maxMemory < MIN_MEMORY_HEAP_SIZE) {
82 | return TinkerUtils.ERROR_PATCH_MEMORY_LIMIT;
83 | }
84 | //or you can mention user to clean their rom space!
85 | if (!checkRomSpaceEnough(roomSize)) {
86 | return TinkerUtils.ERROR_PATCH_ROM_SPACE;
87 | }
88 |
89 | return ShareConstants.ERROR_PATCH_OK;
90 | }
91 |
92 | /**
93 | * 判断是否有Xposed框架的存在
94 | */
95 | public static boolean isXposedExists(Throwable thr) {
96 | StackTraceElement[] stackTraces = thr.getStackTrace();
97 | for (StackTraceElement stackTrace : stackTraces) {
98 | final String clazzName = stackTrace.getClassName();
99 | if (clazzName != null && clazzName.contains("de.robv.android.xposed.XposedBridge")) {
100 | return true;
101 | }
102 | }
103 | return false;
104 | }
105 |
106 | /**
107 | * 判断当前ROM空间是否足够大
108 | */
109 | @Deprecated
110 | public static boolean checkRomSpaceEnough(long limitSize) {
111 | long allSize;
112 | long availableSize = 0;
113 | try {
114 | File data = Environment.getDataDirectory();
115 | StatFs sf = new StatFs(data.getPath());
116 | availableSize = (long) sf.getAvailableBlocks() * (long) sf.getBlockSize();
117 | allSize = (long) sf.getBlockCount() * (long) sf.getBlockSize();
118 | } catch (Exception e) {
119 | allSize = 0;
120 | }
121 |
122 | if (allSize != 0 && availableSize > limitSize) {
123 | return true;
124 | }
125 | return false;
126 | }
127 |
128 | /**
129 | * 获取异常原因字段串
130 | */
131 | public static String getExceptionCauseString(final Throwable ex) {
132 | final ByteArrayOutputStream bos = new ByteArrayOutputStream();
133 | final PrintStream ps = new PrintStream(bos);
134 |
135 | try {
136 | // print directly
137 | Throwable t = ex;
138 | while (t.getCause() != null) {
139 | t = t.getCause();
140 | }
141 | t.printStackTrace(ps);
142 | return toVisualString(bos.toString());
143 | } finally {
144 | try {
145 | bos.close();
146 | } catch (IOException e) {
147 | e.printStackTrace();
148 | }
149 | }
150 | }
151 |
152 | private static String toVisualString(String src) {
153 | boolean cutFlg = false;
154 |
155 | if (null == src) {
156 | return null;
157 | }
158 |
159 | char[] chr = src.toCharArray();
160 | if (null == chr) {
161 | return null;
162 | }
163 |
164 | int i = 0;
165 | for (; i < chr.length; i++) {
166 | if (chr[i] > 127) {
167 | chr[i] = 0;
168 | cutFlg = true;
169 | break;
170 | }
171 | }
172 |
173 | if (cutFlg) {
174 | return new String(chr, 0, i);
175 | } else {
176 | return src;
177 | }
178 | }
179 |
180 | /*------------------ 判断手机是否锁屏状态 ------------------*/
181 | public static class ScreenState {
182 | public interface IOnScreenOff {
183 | void onScreenOff();
184 | }
185 |
186 | public ScreenState(final Context context, final IOnScreenOff onScreenOffInterface) {
187 | IntentFilter filter = new IntentFilter();
188 | filter.addAction(Intent.ACTION_SCREEN_OFF);
189 |
190 | context.registerReceiver(new BroadcastReceiver() {
191 |
192 | @Override
193 | public void onReceive(Context context, Intent in) {
194 | String action = in == null ? "" : in.getAction();
195 | TinkerLog.i(TAG, "ScreenReceiver action [%s] ", action);
196 | if (Intent.ACTION_SCREEN_OFF.equals(action)) {
197 | if (onScreenOffInterface != null) {
198 | onScreenOffInterface.onScreenOff();
199 | }
200 | }
201 | context.unregisterReceiver(this);
202 | }
203 | }, filter);
204 | }
205 | }
206 | }
207 |
--------------------------------------------------------------------------------
/tinker-local/src/main/jniLibs/armeabi-v7a/libLQRJni.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GitLqr/HotFixDemo/865d684b3c1c7b820e753acc8fab298c5ca5d820/tinker-local/src/main/jniLibs/armeabi-v7a/libLQRJni.so
--------------------------------------------------------------------------------
/tinker-local/src/main/jniLibs/armeabi/libLQRJni.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GitLqr/HotFixDemo/865d684b3c1c7b820e753acc8fab298c5ca5d820/tinker-local/src/main/jniLibs/armeabi/libLQRJni.so
--------------------------------------------------------------------------------
/tinker-local/src/main/jniLibs/x86/libLQRJni.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GitLqr/HotFixDemo/865d684b3c1c7b820e753acc8fab298c5ca5d820/tinker-local/src/main/jniLibs/x86/libLQRJni.so
--------------------------------------------------------------------------------
/tinker-local/src/main/res/drawable-v24/ic_launcher_foreground.xml:
--------------------------------------------------------------------------------
1 |
7 |
12 |
13 |
19 |
22 |
25 |
26 |
27 |
28 |
34 |
35 |
--------------------------------------------------------------------------------
/tinker-local/src/main/res/drawable/ic_launcher_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
11 |
16 |
21 |
26 |
31 |
36 |
41 |
46 |
51 |
56 |
61 |
66 |
71 |
76 |
81 |
86 |
91 |
96 |
101 |
106 |
111 |
116 |
121 |
126 |
131 |
136 |
141 |
146 |
151 |
156 |
161 |
166 |
171 |
172 |
--------------------------------------------------------------------------------
/tinker-local/src/main/res/drawable/img_header.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GitLqr/HotFixDemo/865d684b3c1c7b820e753acc8fab298c5ca5d820/tinker-local/src/main/res/drawable/img_header.jpg
--------------------------------------------------------------------------------
/tinker-local/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
13 |
14 |
20 |
21 |
22 |
26 |
27 |
33 |
34 |
35 |
39 |
40 |
41 |
45 |
46 |
47 |
51 |
52 |
56 |
57 |
58 |
64 |
65 |
66 |
72 |
73 |
74 |
78 |
79 |
85 |
86 |
92 |
93 |
94 |
99 |
100 |
104 |
105 |
111 |
112 |
118 |
119 |
120 |
124 |
125 |
131 |
132 |
138 |
139 |
140 |
141 |
--------------------------------------------------------------------------------
/tinker-local/src/main/res/mipmap-anydpi-v26/ic_launcher.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/tinker-local/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/tinker-local/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GitLqr/HotFixDemo/865d684b3c1c7b820e753acc8fab298c5ca5d820/tinker-local/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/tinker-local/src/main/res/mipmap-hdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GitLqr/HotFixDemo/865d684b3c1c7b820e753acc8fab298c5ca5d820/tinker-local/src/main/res/mipmap-hdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/tinker-local/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GitLqr/HotFixDemo/865d684b3c1c7b820e753acc8fab298c5ca5d820/tinker-local/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/tinker-local/src/main/res/mipmap-mdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GitLqr/HotFixDemo/865d684b3c1c7b820e753acc8fab298c5ca5d820/tinker-local/src/main/res/mipmap-mdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/tinker-local/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GitLqr/HotFixDemo/865d684b3c1c7b820e753acc8fab298c5ca5d820/tinker-local/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/tinker-local/src/main/res/mipmap-xhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GitLqr/HotFixDemo/865d684b3c1c7b820e753acc8fab298c5ca5d820/tinker-local/src/main/res/mipmap-xhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/tinker-local/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GitLqr/HotFixDemo/865d684b3c1c7b820e753acc8fab298c5ca5d820/tinker-local/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/tinker-local/src/main/res/mipmap-xxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GitLqr/HotFixDemo/865d684b3c1c7b820e753acc8fab298c5ca5d820/tinker-local/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/tinker-local/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GitLqr/HotFixDemo/865d684b3c1c7b820e753acc8fab298c5ca5d820/tinker-local/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/tinker-local/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GitLqr/HotFixDemo/865d684b3c1c7b820e753acc8fab298c5ca5d820/tinker-local/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/tinker-local/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #3F51B5
4 | #303F9F
5 | #FF4081
6 |
7 |
--------------------------------------------------------------------------------
/tinker-local/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | tinker-local
3 |
4 |
--------------------------------------------------------------------------------
/tinker-local/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/tinker-local/src/test/java/com/lqr/tinker_local/ExampleUnitTest.java:
--------------------------------------------------------------------------------
1 | package com.lqr.tinker_local;
2 |
3 | import org.junit.Test;
4 |
5 | import static org.junit.Assert.*;
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * @see Testing documentation
11 | */
12 | public class ExampleUnitTest {
13 | @Test
14 | public void addition_isCorrect() throws Exception {
15 | assertEquals(4, 2 + 2);
16 | }
17 | }
--------------------------------------------------------------------------------