/* * Created by LuaView. * Copyright (c) 2017, Alibaba Group. All rights reserved. * * This source code is licensed under the MIT. * For the full copyright and license information,please view the LICENSE file in the root directory of this source tree. */ package com.taobao.luaview.scriptbundle.asynctask.delegate; import android.content.Context; import com.taobao.luaview.scriptbundle.ScriptBundle; import com.taobao.luaview.scriptbundle.ScriptFile; import com.taobao.luaview.util.DebugUtil; import com.taobao.luaview.util.DecryptUtil; import com.taobao.luaview.util.IOUtil; import com.taobao.luaview.util.VerifyUtil; import com.taobao.luaview.util.ZipUtil; import org.luaj.vm2.LoadState; import org.luaj.vm2.LuaError; import org.luaj.vm2.Prototype; import java.io.BufferedInputStream; import java.io.ByteArrayInputStream; import java.io.InputStream; import java.util.Map; /** * ScriptBundle Load Delegate * * @author song * @date 17/2/8 * 主要功能描述 * 修改描述 * 下午2:44 song XXX */ public class ScriptBundleLoadDelegate { public ScriptBundleLoadDelegate() { } public ScriptBundle load(Context context, ScriptBundle scriptBundle) { if (scriptBundle != null && scriptBundle.size() > 0 && verifyAllScripts(context, scriptBundle)) {//强校验,如果脚本存在并且校验成功才返回 Map<String, ScriptFile> files = scriptBundle.getScriptFileMap(); ScriptFile scriptFile = null; for (String key : files.keySet()) { scriptFile = files.get(key); scriptFile.scriptData = loadEncryptScript(context, scriptBundle.isBytecode(), scriptFile); if (scriptBundle.isBytecode()) {//如果是bytecode,则加载prototype DebugUtil.tsi("luaviewp-loadPrototype"); scriptFile.prototype = loadPrototype(scriptFile); // TODO 性能瓶颈 DebugUtil.tei("luaviewp-loadPrototype"); } } return scriptBundle; } else { return null; } } //------------------------------------------加载脚本函数------------------------------------------ /** * load a prototype * * @param scriptFile * @return */ private Prototype loadPrototype(final ScriptFile scriptFile) { if (LoadState.instance != null && scriptFile != null) { try { return LoadState.instance.undump(new BufferedInputStream(new ByteArrayInputStream(scriptFile.scriptData)), scriptFile.getFilePath());//TODO 低端机性能上可以进一步优化 } catch (LuaError error) { error.printStackTrace(); } catch (Exception e) { e.printStackTrace(); } } return null; } /** * 加载一个脚本 * * @param context * @return */ public static InputStream loadEncryptScript(final Context context, final InputStream inputStream) { if (inputStream != null) { InputStream result = new ByteArrayInputStream(ZipUtil.unzip(DecryptUtil.aes(context, IOUtil.toBytes(inputStream)))); try { inputStream.close(); } catch (Exception e) {//close input, 这里需要注意,外面不能使用该inputStream } return result; } return inputStream; } /** * 加载加密过的脚本 * * @param context * @param scriptFile * @return */ private static byte[] loadEncryptScript(final Context context, final boolean isBytecode, final ScriptFile scriptFile) { if (scriptFile != null) { if (isBytecode) {//bytecode不进行unzip if (scriptFile.signData != null && scriptFile.signData.length > 0) {//加密过则进行解密并unzip return DecryptUtil.aes(context, scriptFile.scriptData); } else { return scriptFile.scriptData; } } else { if (scriptFile.signData != null && scriptFile.signData.length > 0) {//加密过则进行解密并unzip return ZipUtil.unzip(DecryptUtil.aes(context, scriptFile.scriptData)); } else { return ZipUtil.unzip(scriptFile.scriptData); } } } return null; } /** * 加载加密过的脚本 * * @param context * @param script * @return */ private static byte[] loadEncryptScript(final Context context, final byte[] script) { return ZipUtil.unzip(DecryptUtil.aes(context, script)); } /** * 验证所有脚本,有任何一个失败则返回失败 * * @param bundle * @return */ private static boolean verifyAllScripts(Context context, ScriptBundle bundle) { Map<String, ScriptFile> files = bundle != null ? bundle.getScriptFileMap() : null; if (files != null) { for (final String key : files.keySet()) { if (verifyScript(context, bundle.isBytecode(), files.get(key)) == false) { return false; } } } return true; } /** * 验证一个脚本 * * @param isBytecode * @param script * @return */ private static boolean verifyScript(Context context, boolean isBytecode, ScriptFile script) { if (script != null) { if (isBytecode) {//bytecode 模式下,如果没有signdata也算验证通过 if (script.signData != null && script.signData.length > 0) { return VerifyUtil.rsa(context, script.scriptData, script.signData); } return true; } else { return VerifyUtil.rsa(context, script.scriptData, script.signData); } } return false; } }