Java源码示例:com.qihoo360.replugin.model.PluginInfo

示例1
private void install(){
        AssetManager assets = this.getAssets();
//        String path = "file:///android_asset/app-release.apk";
        String dest = Environment.getExternalStorageDirectory().getAbsolutePath() + File.separator+ "app-release.apk";
        PluginInfo pluginInfo = RePlugin.install(dest);
        Log.e(TAG,"pluginInfo:"+pluginInfo);
        if (pluginInfo != null) {
            Toast.makeText(MainActivity.this, "插件安装成功",Toast.LENGTH_SHORT).show();
            boolean preload = RePlugin.preload(pluginInfo);
            if (preload){
                Toast.makeText(MainActivity.this, "预加载完成", Toast.LENGTH_SHORT).show();
            } else {
                Toast.makeText(MainActivity.this, "插件安装失败",Toast.LENGTH_SHORT).show();
            }
        }
    }
 
示例2
/**
 * @param action
 */
private final void registerReceiverAction(final String action) {
    IntentFilter filter = new IntentFilter(action);
    LocalBroadcastManager.getInstance(mContext).registerReceiver(new BroadcastReceiver() {

        @Override
        public void onReceive(Context context, Intent intent) {
            if (action.equals(intent.getAction())) {
                PluginInfo info = intent.getParcelableExtra("obj");
                if (info != null) {
                    switch (action) {
                        case ACTION_NEW_PLUGIN:
                            // 非常驻进程上下文
                            newPluginFound(info, intent.getBooleanExtra(RePluginConstants.KEY_PERSIST_NEED_RESTART, false));
                            break;
                        case ACTION_UNINSTALL_PLUGIN:
                            pluginUninstalled(info);
                            break;
                    }
                }
            }
        }
    }, filter);
}
 
示例3
/**
 * 模拟安装外置插件
 * 注意:为方便演示,外置插件临时放置到Host的assets/external目录下,具体说明见README</p>
 *
 * @param pluginName 待安装的插件名
 */
private void simulateInstallExternalPlugin(String pluginName) {
    PluginInfo info = RePlugin.getPluginInfo(pluginName);
    if (info == null) {
        String pluginFilePath = getFilesDir().getAbsolutePath() + File.separator + PLUGIN_APK;
        File pluginFile = new File(pluginFilePath);
        if (!pluginFile.exists()) {
            copyAssetsFileToAppFiles(PLUGIN_PATH, PLUGIN_APK);
            if (pluginFile.exists()) {
                info = RePlugin.install(pluginFilePath);
            }
        }
    }

    if (info != null) {
        RePlugin.startActivity(MainActivity.this, RePlugin.createIntent(info.getName(), "com.qihoo360.replugin.sample.demo3.MainActivity"));
    } else {
        Toast.makeText(MainActivity.this, "install external plugin failed", Toast.LENGTH_SHORT).show();
    }
}
 
示例4
/**
 * 安装此插件 <p>
 * 注意: <p>
 * 1、这里只将APK移动(或复制)到“插件路径”下,不释放优化后的Dex和Native库,不会加载插件 <p>
 * 2、支持“纯APK”和“p-n”(旧版,即将废弃)插件 <p>
 * 3、此方法是【同步】的,耗时较少
 *
 * @param path 插件安装的地址。必须是“绝对路径”。通常可以用context.getFilesDir()来做
 * @return 安装成功的插件信息,外界可直接读取
 * @since 2.0.0 (1.x版本为installDelayed)
 */
public static PluginInfo install(String path) {
    if (!RePluginFramework.mHostInitialized) {
        return null;
    }

    try {
        Object obj = ProxyRePluginVar.install.call(null, path);
        if (obj != null) {
            // 跨ClassLoader进行parcel对象的构造
            Parcel p = ParcelUtils.createFromParcelable((Parcelable) obj);
            return PluginInfo.CREATOR.createFromParcel(p);
        }
    } catch (Exception e) {
        if (LogDebug.LOG) {
            e.printStackTrace();
        }
    }
    return null;
}
 
示例5
/**
 * 预加载此插件。此方法会立即释放优化后的Dex和Native库,但不会运行插件代码。 <p>
 * 使用场景:在“安装”完成后“提前释放Dex”(时间算在“安装过程”中)。这样下次启动插件时则速度飞快 <p>
 * 注意: <p>
 * 1、该方法非必须调用(见“使用场景”)。换言之,只要涉及到插件加载,就会自动完成preload操作,无需开发者关心 <p>
 * 2、Dex和Native库会占用大量的“内部存储空间”。故除非插件是“确定要用的”,否则不必在安装完成后立即调用此方法 <p>
 * 3、该方法为【同步】调用,且耗时较久(尤其是dex2oat的过程),建议在线程中使用
 *
 * @param pi 要加载的插件信息
 * @return 预加载是否成功
 * @hide
 * @see #install(String)
 * @since 2.0.0
 */
public static boolean preload(PluginInfo pi) {
    if (!RePluginFramework.mHostInitialized) {
        return false;
    }

    try {
        // 跨classloader创建PluginInfo对象
        // TODO 如果有更优雅的方式,可优化
        Object p = ParcelUtils.createFromParcelable(pi, RePluginEnv.getHostCLassLoader(), "com.qihoo360.replugin.model.PluginInfo");
        Object obj = ProxyRePluginVar.preload2.call(null, p);
        if (obj != null) {
            return (Boolean) obj;
        }
    } catch (Exception e) {
        if (LogDebug.LOG) {
            e.printStackTrace();
        }
    }

    return false;
}
 
示例6
/**
 * 获取指定插件的信息
 *
 * @param name 插件名
 * @return PluginInfo对象
 * @since 1.2.0
 */
public static PluginInfo getPluginInfo(String name) {
    if (!RePluginFramework.mHostInitialized) {
        return null;
    }

    try {
        Object obj = ProxyRePluginVar.getPluginInfo.call(null, name);
        if (obj != null) {
            // 跨ClassLoader进行parcel对象的构造
            Parcel p = ParcelUtils.createFromParcelable((Parcelable) obj);
            return PluginInfo.CREATOR.createFromParcel(p);
        }
    } catch (Exception e) {
        if (LogDebug.LOG) {
            e.printStackTrace();
        }
    }

    return null;
}
 
示例7
/**
 * @deprecated 待优化
 * 插件进程调度
 * @param plugin
 * @param process
 * @return
 */
@Deprecated
static final int allocProcess(String plugin, int process) {
    if (AppConstant.PLUGIN_NAME_UI.equals(plugin) || process == IPluginManager.PROCESS_UI) {
        return IPluginManager.PROCESS_UI;
    }

    if (PluginProcessHost.isCustomPluginProcess(process)) {
        return process;
    }

    PluginInfo info = PluginTable.getPluginInfo(plugin);
    if (info == null) {
        if (LOG) {
            LogDebug.d(PLUGIN_TAG, "alloc process: plugin not found: name=" + plugin);
        }
        return IPluginManager.PROCESS_AUTO;
    }

    synchronized (PROCESSES) {
        return allocProcessLocked(plugin);
    }
}
 
示例8
final void pluginUninstalled(PluginInfo info) {
    if (LOG) {
        LogDebug.d(PLUGIN_TAG, "Clear plugin cache. pn=" + info.getName());
    }

    // 移除卸载插件的HashMap缓存
    if (mPlugins.containsKey(info.getName())) {
        mPlugins.remove(info.getName());
    }

    // 移除卸载插件表快照
    PluginTable.removeInfo(info);

    // 移除内存中插件的PackageInfo、Resources、ComponentList和DexClassLoader缓存对象
    AllPluginsInfoPool.clearCachedPlugin(AllPluginsInfoPool.queryCachedFilename(info.getName()));
}
 
示例9
private void updateAllIfNeeded() {
    // FIXME 务必保证sync方法被调用,否则有可能判断不准确
    int updateNum = 0;
    for (PluginInfo pi : mList) {
        if (updateIfNeeded(pi)) {
            updateNum++;
        }
    }

    if (LogDebug.LOG) {
        LogDebug.d(TAG, "updateAllIfNeeded: Updated " + updateNum + " plugins");
    }
    if (updateNum > 0) {
        mList.save(mContext);
    }
}
 
示例10
private void updateNow(PluginInfo curInfo, PluginInfo newInfo) {
    final boolean covered = newInfo.getIsPendingCover();
    if (covered) {
        move(curInfo, newInfo);
    } else {
        // 删除旧版本插件,不管是不是p-n的,且清掉Dex和Native目录
        delete(curInfo);
    }

    newInfo.setType(PluginInfo.TYPE_EXTRACTED);
    if (LogDebug.LOG) {
        LogDebug.i(TAG, "updateNow: Update. pn=" + curInfo.getVersion() +
                "; cur_ver=" + curInfo.getVersion() + "; update_ver=" + newInfo.getVersion());
    }

    if (covered) {
        curInfo.setPendingCover(null);
    } else {
        curInfo.update(newInfo);
        curInfo.setPendingUpdate(null);
    }
}
 
示例11
/**
 * 提取文件到目标位置,并处理文件夹是否存在,是否校验,是否强制覆盖,是否需要释放SO库
 * @param context
 * @param info PluginInfo对象(asset的相对路径,可包含子路径)
 * @param dir 目标文件夹(asset的输出目录)
 * @param dexOutputDir 成功提取该文件时,是否删除同名的DEX文件
 * @return
 */
public static final boolean quickExtractTo(Context context, final PluginInfo info, final String dir, final String dstName, String dexOutputDir) {
    QuickExtractResult result = quickExtractTo(context, info.getPath(), dir, dstName, dexOutputDir);
    // 释放失败 || 被释放的文件已经存在
    switch (result) {
        case FAIL:
            return false;
        case EXISTED:
            return true;
        default:
            // 释放插件里的Native(SO)库文件
            // Added by Jiongxuan Zhang
            File file = new File(dir + "/" + dstName);
            File libDir = info.getNativeLibsDir();
            boolean rc = PluginNativeLibsHelper.install(file.getAbsolutePath(), libDir);
            if (!rc) {
                if (LOGR) {
                    LogRelease.e(TAG, "a u e rc f so " + file.getPath());
                }
                return rc;
            }
            return true;
    }
}
 
示例12
/**
 * 常驻进程进行插件卸载
 *
 * @param pi
 */
public static boolean uninstall(PluginInfo pi) throws RemoteException {
    if (pi == null) {
        // 不太可能到这里
        return false;
    }
    if (pi.isPnPlugin()) {
        // 是常驻进程?老逻辑直接走dex文件存在判断,也无需做处理
        return false;
    }

    if (sRemote == null) {
        // 常驻已挂掉,可以认为无需处理
        if (LogRelease.LOGR) {
            LogRelease.e(PLUGIN_TAG, "pmc.uuin: s=null");
        }
        return false;
    }

    return sRemote.uninstall(pi);
}
 
示例13
private int install(ContentValues cv) {
    if (cv == null) {
        return 0;
    }

    String pit = cv.getAsString(KEY_PLUGIN_INFO);
    if (TextUtils.isEmpty(pit)) {
        return 0;
    }
    PluginInfo pi = PluginInfo.parseFromJsonText(pit);

    // 开始加载ClassLoader
    ClassLoader cl = PluginMgrFacade.getLocal().loadPluginClassLoader(pi);
    if (cl != null) {
        return 1;
    } else {
        return 0;
    }
}
 
示例14
static final void replaceInfo(PluginInfo info) {
    boolean rc = false;
    PluginInfo pi = null;
    synchronized (PLUGINS) {
        pi = PLUGINS.get(info.getName());
        if (pi != null) {
            if (pi.canReplaceForPn(info)) {
                putPluginInfo(info);
                rc = true;
            }
        }
    }
    if (LOG) {
        LogDebug.d(PLUGIN_TAG, "replace plugin table: info=" + info + " rc=" + rc);
    }
}
 
示例15
@Override
public boolean pluginExtracted(String path) throws RemoteException {
    if (LOG) {
        LogDebug.d(PLUGIN_TAG, "pluginExtracted: path=" + path);
    }

    //
    File f = new File(path);

    PluginInfo info = PluginInfo.build(f);
    if (info == null) {
        return false;
    }

    // 常驻进程上下文
    mPluginMgr.newPluginFound(info, false);

    // 通知其它进程
    Intent intent = new Intent(PluginMgr.ACTION_NEW_PLUGIN);
    intent.putExtra(RePluginConstants.KEY_PERSIST_NEED_RESTART, mNeedRestart);
    intent.putExtra("obj", info);
    IPC.sendLocalBroadcast2AllSync(mContext, intent);

    return true;
}
 
示例16
static final void updatePlugin(PluginInfo info) {
    if (LOG) {
        LogDebug.d(PLUGIN_TAG, "update plugin table: info=" + info);
    }
    synchronized (PLUGINS) {

        // 检查插件是否已经被禁用
        if (RePlugin.getConfig().getCallbacks().isPluginBlocked(info)) {
            if (LOG) {
                LogDebug.d(PLUGIN_TAG, "update plugin table: plugin is blocked, in=" + info);
            }
            return;
        }

        // 此处直接使用该插件,没有考虑是否只采用最新版
        putPluginInfo(info);
    }
}
 
示例17
/**
 * 确保版本和插件唯一
 * @param array
 * @param info
 * @param replace true表示更新相同的,false表示不更新相同的
 * @return
 */
private final boolean insert(ArrayList<PluginInfo> array, PluginInfo info, boolean replace) {
    for (int i = 0; i < array.size(); i++) {
        PluginInfo pi = array.get(i);
        // 存在
        if (pi.getName().equals(info.getName())) {
            // 忽略
            if (replace) {
                if (PluginInfo.VERSION_COMPARATOR.compare(pi, info) > 0) {
                    return false;
                }
            } else {
                if (PluginInfo.VERSION_COMPARATOR.compare(pi, info) >= 0) {
                    return false;
                }
            }
            // 更新
            others.add(array.get(i));
            array.set(i, info);
            return true;
        }
    }
    // 不存在,添加
    array.add(info);
    return true;
}
 
示例18
/**
 * @param info
 * @return
 */
final void addNormal(PluginInfo info) {
    PluginInfo pi = null;
    // FIXME 用all表
    if ((pi = getBuiltin(info.getName())) != null && pi.getVersionValue() == info.getVersionValue()) {
        if (LOG) {
            LogDebug.d(PLUGIN_TAG, "builtin plugin: normal=" + info);
        }
    } else if ((pi = getV5(info.getName())) != null && pi.getVersionValue() == info.getVersionValue()) {
        if (LOG) {
            LogDebug.d(PLUGIN_TAG, "v5 plugin: normal=" + info);
        }
    } else {
        others.add(info);
        return;
    }

    insert(normals, info, false);
}
 
示例19
private static void deleteUnknownDexs(Context context, PxAll all) {
    HashSet<String> names = new HashSet<>();
    for (PluginInfo p : all.getPlugins()) {
        names.add(p.getDexFile().getName());
    }
    File dir = context.getDir(AppConstant.LOCAL_PLUGIN_ODEX_SUB_DIR, 0);
    File files[] = dir.listFiles();
    if (files != null) {
        for (File f : files) {
            if (names.contains(f.getName())) {
                continue;
            }
            if (LOG) {
                LogDebug.d(PLUGIN_TAG, "delete unknown dex=" + f.getAbsolutePath());
            }
            try {
                FileUtils.forceDelete(f);
            } catch (IOException e) {
                if (LOG) {
                    LogDebug.d(PLUGIN_TAG, "can't delete unknown dex=" + f.getAbsolutePath(), e);
                }
            }
        }
    }
}
 
示例20
private static void deleteUnknownLibs(Context context, PxAll all) {
    HashSet<String> names = new HashSet<>();
    for (PluginInfo p : all.getPlugins()) {
        names.add(p.getNativeLibsDir().getName());
    }

    File dir = context.getDir(AppConstant.LOCAL_PLUGIN_DATA_LIB_DIR, 0);
    File files[] = dir.listFiles();
    if (files != null) {
        for (File f : files) {
            if (names.contains(f.getName())) {
                continue;
            }
            if (LOG) {
                LogDebug.d(PLUGIN_TAG, "delete unknown libs=" + f.getAbsolutePath());
            }
            try {
                FileUtils.forceDelete(f);
            } catch (IOException e) {
                if (LOG) {
                    LogDebug.d(PLUGIN_TAG, "can't delete unknown libs=" + f.getAbsolutePath(), e);
                }
            }
        }
    }
}
 
示例21
@Override
public void onObserveViewModel(@NonNull SettingsViewModel viewModel) {
    super.onObserveViewModel(viewModel);
    binding.setSettingsViewModel(viewModel);
    viewModel.cacheSize.set(FileUtil.getCacheSizeStr(this));
    int pluginNum = 0;
    for (PluginInfo pluginInfo : RePlugin.getPluginInfoList()) {
        pluginNum += pluginInfo.isUsed() ? 1 : 0;
    }
    viewModel.pluginNum.set(pluginNum);
}
 
示例22
@Override
public void install(Context context, String filename, Update update) {
    PluginInfo info = RePlugin.install(filename);
    if (!info.getAlias().equals(pluginName)) {
        // 校验是否插件的别名能匹配上。将不正确的卸载掉
        Toast.makeText(context, String.format("install plugin failed: need alias for %s but is %s", pluginName, info.getAlias()), Toast.LENGTH_SHORT).show();
        RePlugin.uninstall(info.getAlias());
    } else {
        RePlugin.startActivity(this.context, intent);
    }
}
 
示例23
/**
 * 获取所有插件的列表(指已安装的)
 *
 * @return PluginInfo的表
 * @since 2.0.0(1.x版本为getExistPlugins)
 */
public static List<PluginInfo> getPluginInfoList() {
    if (!RePluginFramework.mHostInitialized) {
        return null;
    }

    try {
        List list = (List) ProxyRePluginVar.getPluginInfoList.call(null);
        if (list != null && list.size() > 0) {
            List<PluginInfo> ret = new ArrayList<>();
            for (Object o : list) {
                // 跨ClassLoader进行parcel对象的构造
                Parcel p = ParcelUtils.createFromParcelable((Parcelable) o);
                PluginInfo nPi = PluginInfo.CREATOR.createFromParcel(p);
                ret.add(nPi);
            }

            return ret;
        }
    } catch (Exception e) {
        if (LogDebug.LOG) {
            e.printStackTrace();
        }
    }

    return null;
}
 
示例24
/**
 * 预加载此插件。此方法会立即释放优化后的Dex和Native库,但不会运行插件代码。 <p>
 * 具体用法可参见preload(PluginInfo)的说明
 *
 * @param pluginName 要加载的插件名
 * @return 预加载是否成功
 * @see #preload(PluginInfo)
 * @since 2.0.0
 */
public static boolean preload(String pluginName) {
    PluginInfo pi = getPluginInfo(pluginName);
    if (pi == null) {
        // 插件不存在,无法加载Dex
        if (LogDebug.LOG) {
            LogDebug.e(TAG, "preload: Plugin not found! pn=" + pluginName);
        }
        return false;
    }
    return preload(pi);
}
 
示例25
/**
 * 获取当前插件的版本号,可以是VersionCode,也可以是meta-data中的ver。
 *
 * @param name 插件名
 * @return 插件版本号。若为-1则表示插件不存在
 * @since 2.0.0
 */
public static int getPluginVersion(String name) {
    PluginInfo pi = RePluginOS.getPlugin(name, false);
    if (pi == null) {
        return -1;
    }

    return pi.getVersion();
}
 
示例26
private boolean onInstall(String path, boolean immediately) {
    PluginInfo pi = RePlugin.install(path);

    // Okay
    if (pi != null) {
        if (LogDebug.LOG) {
            LogDebug.i(TAG, "onInstall: Install Success! cur=" + RePlugin.getPluginInfo(pi.getName()));
        }

        if (immediately) {
            if (RePlugin.preload(pi)) {
                if (LogDebug.LOG) {
                    LogDebug.i(TAG, "onInstall: Preload Success! pn=" + pi.getName());
                }
                return true;
            } else {
                if (LogDebug.LOG) {
                    LogDebug.e(TAG, "onInstall: Preload Error! pn=" + pi.getName());
                }
            }
        }
    } else {
        if (LogDebug.LOG) {
            LogDebug.e(TAG, "onInstall: Install Error! path=" + path);
        }
    }
    return false;
}
 
示例27
private List<PluginInfo> loadLocked() {
    if (!mList.load(mContext)) {
        return null;
    }

    // 执行“更新或删除Pending”插件,并返回结果
    return updateAllLocked();
}
 
示例28
private List<PluginInfo> updateAllLocked() {
    // 判断是否需要更新插件(只有未运行的才可以)
    updateAllIfNeeded();

    // TODO 扫描一下,看看文件在不在
    return mList.cloneList();
}
 
示例29
/**
 * 插件卸载
 * 判断插件是否已安装:插件未安装,不做处理
 * 插件已安装,正在运行,则记录“卸载状态”,推迟到到主程序进程重启的时执行卸载
 * 插件已安装,未在运行,则直接删除Dex、Native库等资源
 *
 * @param pluginName
 * @return 插件卸载成功与否
 */
public static final boolean pluginUninstall(String pluginName) {
    if (LOG) {
        LogDebug.d(PLUGIN_TAG, "RePluginOS.pluginUninstall ... pluginName=" + pluginName);
    }
    PluginInfo pi = getPlugin(pluginName, true);

    // 插件未安装
    if (pi == null) {
        if (LOG) {
            LogDebug.d(PLUGIN_TAG, "Not installed. pluginName=" + pluginName);
        }
        return true;
    }

    // 插件已安装
    try {
        return PluginManagerProxy.uninstall(pi);
    } catch (RemoteException e) {
        e.printStackTrace();
        if (LOG) {
            e.printStackTrace();
        }
    }

    return false;
}
 
示例30
private static void putPluginInfo(PluginInfo info) {
    // 同时加入PackageName和Alias(如有)
    PLUGINS.put(info.getPackageName(), info);
    if (!TextUtils.isEmpty(info.getAlias())) {
        // 即便Alias和包名相同也可以再Put一次,反正只是覆盖了相同Value而已
        PLUGINS.put(info.getAlias(), info);
    }
}