diff --git a/libp2pimpl/src/main/java/cn/vbyte/p2p/VbyteP2PModule.java b/libp2pimpl/src/main/java/cn/vbyte/p2p/VbyteP2PModule.java index ef606cb..7cafb2a 100644 --- a/libp2pimpl/src/main/java/cn/vbyte/p2p/VbyteP2PModule.java +++ b/libp2pimpl/src/main/java/cn/vbyte/p2p/VbyteP2PModule.java @@ -6,13 +6,11 @@ import android.os.Message; import android.os.Handler; import android.telephony.TelephonyManager; +import android.text.TextUtils; import android.util.Log; import java.lang.ref.WeakReference; import java.util.Arrays; -import java.util.HashMap; -import java.util.List; -import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; @@ -22,7 +20,17 @@ * Created by passion on 15-11-5. */ public final class VbyteP2PModule { - private static final String DYNAMIC_LIB_NAME = "libp2pmodule"; + private static final String LIB_P2PMODULE_SO = "libp2pmodule"; + + /** + * libp2pmodule的jni接口版本 + */ + private final String P2PMODULE_JNI_VERSION = "v3"; + + /** + * 无JNI接口的JNI版(这是检查so升级必须的参数) + */ + public final String OTHTER_JNI_VERSION = "v0"; public static class Event { /** @@ -159,8 +167,8 @@ public static VbyteP2PModule getInstance() { } /** - * 获取native应用的版本号 - * @return P2PModule SDK的版本号 + * 获取p2p-sdk so库的版本号 + * @return p2p-sdk so库的版本号 */ public static String getVersion() { if (SDK_VERSION == null) { @@ -182,7 +190,7 @@ private static boolean isArchValid(String arch) { * 返回5种架构中的一个获取null */ public static String getArchABI() { - if(archCpuAbi.isEmpty()) { + if(TextUtils.isEmpty(archCpuAbi)) { archCpuAbi = VbyteP2PModule._targetArchABI(); } return isArchValid(archCpuAbi) ? archCpuAbi : ""; @@ -247,40 +255,76 @@ public static void setLoggerCallback(LoggerCallback logger) { private long _pointer; private WeakReference _context; - private VbyteP2PModule(Context context, String appId, String appKey, String appSecretKey) - throws Exception { - if (context == null || appId == null || appKey == null || appSecretKey == null) { - throw new NullPointerException("context or appId or appKey or appSecretKey can't be null when init p2p live stream!"); + /** + * 加载so + * @param context + * @param soNameWithoutSuffix so名称(不带后缀) + * @param jniVersion JNI版本(目前仅p2p的so才有jni接口),若该值为空则默认为 OTHTER_JNI_VERSION = 'v0' + */ + public void loadSo(Context context, String soNameWithoutSuffix, String jniVersion) { + + if (TextUtils.isEmpty(soNameWithoutSuffix)) { + return; } - System.loadLibrary("stun"); - System.loadLibrary("event"); + if (dynamicLibManager == null) { + dynamicLibManager = new DynamicLibManager(context); + } + + if (TextUtils.isEmpty(jniVersion)) { + jniVersion = OTHTER_JNI_VERSION; + } + + dynamicLibManager.ensureLibDir(jniVersion); + + doLoadSo(soNameWithoutSuffix); + } + + private void doLoadSo(String soNameWithoutSuffix) { /** * * 能从jni里面获取到arch, 就进行下面的升级、加载,否则加载lib/ 下的libp2pmodule * android.os.Build.CPU_ABI、android.os.Build.SUPPORT_ABIS不靠谱,很多机型获取不到,不能用这个。因此,不用这个获取。 * archCpuAbi再次验证一下 */ - String soFilePath = null; - dynamicLibManager = new DynamicLibManager(context); - try { //这里加一个check libp2pmodule文件的md5值,因为应用目录/files目录下 很可能被别的应用扫描到给破坏了就load错误了 - soFilePath = dynamicLibManager.locate(DYNAMIC_LIB_NAME); + soFilePath = dynamicLibManager.locate(soNameWithoutSuffix); } catch (Exception e) { // 因获取不到程序版本号而导致的自动升级失败,默认使用安装时自带的 } if (soFilePath == null) { - System.loadLibrary("p2pmodule"); + if (soNameWithoutSuffix.startsWith("lib")) { + String libNameWithoutPreffix = soNameWithoutSuffix.substring(3); + System.loadLibrary(libNameWithoutPreffix); + } } else { System.load(soFilePath); } + } - if(!getArchABI().isEmpty()) { + private void checkUpdate(String soNameWithoutSuffix, String nativeVersion, String jniVersion) { + if(!TextUtils.isEmpty(getArchABI())) { //得到了arch, 开始check升级用false即可 - dynamicLibManager.checkUpdateV2(false, "libp2pmodule_" + VbyteP2PModule.getVersion() + "_20170928.so", getArchABI()); + dynamicLibManager.checkUpdateV2(false, soNameWithoutSuffix, nativeVersion, jniVersion, getArchABI()); } + } + + private VbyteP2PModule(Context context, String appId, String appKey, String appSecretKey) + throws Exception { + if (context == null || appId == null || appKey == null || appSecretKey == null) { + throw new NullPointerException("context or appId or appKey or appSecretKey can't be null when init p2p live stream!"); + } + + System.loadLibrary("stun"); + System.loadLibrary("event"); + + //加载 libp2pmodule.so + loadSo(context, LIB_P2PMODULE_SO, P2PMODULE_JNI_VERSION); + + //检查升级 libp2pmodule.so + checkUpdate(LIB_P2PMODULE_SO, VbyteP2PModule.getVersion(), P2PMODULE_JNI_VERSION); _pointer = this._construct(); if (_pointer == 0) { diff --git a/libp2pimpl/src/main/java/com/vbyte/update/DynamicLibManager.java b/libp2pimpl/src/main/java/com/vbyte/update/DynamicLibManager.java index 11ab266..334efee 100644 --- a/libp2pimpl/src/main/java/com/vbyte/update/DynamicLibManager.java +++ b/libp2pimpl/src/main/java/com/vbyte/update/DynamicLibManager.java @@ -4,6 +4,7 @@ import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.text.TextUtils; +import android.util.Log; import org.json.JSONObject; import java.io.BufferedInputStream; @@ -31,8 +32,6 @@ public class DynamicLibManager { private String libDirPath; private String currentLibDirPath; - //jni接口版本 - private String jniVersion = "v3"; //非https要下载的so private String[] soNameArr = new String[]{"libp2pmodule", "libstun", "libevent"}; private boolean supportHttps = false; @@ -40,13 +39,11 @@ public class DynamicLibManager { private String[] soNameArrSupportHttps = new String[]{"libp2pmodule", "libstun", "libevent", "libevent_openssl", "libcrypto", "libssl"}; private static String archCpuAbi = ""; - /** - * cpuArch为传进来的,让这个类可以不依赖外面的类,cpuArch为 armeabi、armeabi-v7a、armeabi-v8a、x86、x86_64中的一个 - * @param context - */ - public DynamicLibManager(Context context) { - this.context = context; - libDirPath = this.context.getFilesDir().getAbsolutePath() + File.separator + "vlib"; + public void ensureLibDir(String jniVersion) { + + if (!TextUtils.isEmpty(currentLibDirPath)) { + return; + } StringBuilder tmpCurrentLibDirPath = new StringBuilder(); tmpCurrentLibDirPath.append(context.getFilesDir().getAbsolutePath()) @@ -121,6 +118,16 @@ public boolean accept(File file) { } } + + /** + * cpuArch为传进来的,让这个类可以不依赖外面的类,cpuArch为 armeabi、armeabi-v7a、armeabi-v8a、x86、x86_64中的一个 + * @param context + */ + public DynamicLibManager(Context context) { + this.context = context; + libDirPath = this.context.getFilesDir().getAbsolutePath() + File.separator + "vlib"; + } + public boolean isSoReady() { //如果ready存在, files/vlib/当前jniVersion/当前armeabi/ready 那么hasAllJniSo = true File currentLibDir = new File(currentLibDirPath); @@ -134,8 +141,19 @@ public boolean isSoReady() { } } - //第一次升级, true "", 第二次只检查libp2pmodule的升级 - public void checkUpdateV2(final boolean firstDownload, final String soName, final String arch) { + /** + * 检查升级,目前在两种场景下使用 + * 1.南瓜首次运行下载所有的so.(南瓜对size有要求) + * 2.p2p-sdk的so升级 + * @param downloadAllSo true 下载所有的so + * false 升级soNameWithoutSubffix指定的so + * @param soNameWithoutSuffix 不带后缀名的so名称 + * @param nativeVersion so的版本 + * @param jniVersion JNI接口版本,当前仅对libp2pmodule这个so有效(只有它有jni接口) + * @param arch 架构名称,例如armeabi|armeabi-v7a|arm64-v8a|x86|x86_64 + */ + public void checkUpdateV2(final boolean downloadAllSo, final String soNameWithoutSuffix, final String nativeVersion, final String jniVersion, final String arch) { + /** * 只有第一次下载的情况下,currentPath没有 endWith /armeabi-v7a * 此时currentLibDirPath为 @@ -172,18 +190,18 @@ public void run() { sb.append("&supportHttps=true"); soNameArr = soNameArrSupportHttps; } - if (firstDownload) { + if (downloadAllSo) { sb.append("&fileId=").append(TextUtils.join(",", soNameArr)); } else { - String[] tmpArr = soName.split("_"); - if (tmpArr.length == 3) { - sb.append("&fileId=").append("libp2pmodule") - .append("&fifoVersion=").append(tmpArr[1]); - } else { + if (TextUtils.isEmpty(soNameWithoutSuffix) || TextUtils.isEmpty(nativeVersion)) { return; + } else { + sb.append("&fileId=").append(soNameWithoutSuffix) + .append("&fifoVersion=").append(nativeVersion); } } + URL url = new URL(sb.toString()); HttpURLConnection conn = (HttpURLConnection) url.openConnection(); @@ -202,21 +220,20 @@ public void run() { if (jsonObj.has("downloadUrl")) { String[] downloadSoArr; - if (firstDownload) { + if (downloadAllSo) { downloadSoArr = soNameArr; } else { - downloadSoArr = new String[]{"libp2pmodule"}; + downloadSoArr = new String[]{soNameWithoutSuffix}; } Map soJsonMap = new HashMap<>(); JSONObject jsonObjDownload = jsonObj.getJSONObject("downloadUrl"); - for (String soName : downloadSoArr) { if (jsonObjDownload.has(soName)) { JSONObject jsonObjTmp = jsonObjDownload.getJSONObject(soName); - if (soName.equals("libp2pmodule")) { + if (soName.equals(soNameWithoutSuffix)) { //如果是libp2pmodule还检查jniVersion字段 if (jsonObjTmp.has("jniVersion") && !TextUtils.isEmpty(jsonObjTmp.getString("jniVersion")) @@ -249,7 +266,7 @@ public void run() { JSONObject jsonObject = entry.getValue(); writeReady = (writeReady && updateDynamicLib(entry.getKey(), jsonObject.getString("url"), jsonObject.getString("version"), jsonObject.getString("md5token"))); } - if (firstDownload && writeReady) { + if (downloadAllSo && writeReady) { //第一次下载且都下载成功创建文件标识符 new File(currentLibDirPath + File.separator + "ready").createNewFile(); }