/**
   * 构造插件信息
   *
   * @param
   */
  static void ensurePluginInited(PluginDescriptor pluginDescriptor) {
    if (pluginDescriptor != null) {
      DexClassLoader pluginClassLoader = pluginDescriptor.getPluginClassLoader();
      if (pluginClassLoader == null) {
        LogUtil.d("正在初始化插件Resources, DexClassLoader, Context, Application ");

        LogUtil.d("是否为独立插件", pluginDescriptor.isStandalone());

        Resources pluginRes =
            PluginCreator.createPluginResource(
                sApplication, pluginDescriptor.getInstalledPath(), pluginDescriptor.isStandalone());

        pluginClassLoader =
            PluginCreator.createPluginClassLoader(
                pluginDescriptor.getInstalledPath(), pluginDescriptor.isStandalone());
        Context pluginContext =
            PluginCreator.createPluginApplicationContext(
                pluginDescriptor, sApplication, pluginRes, pluginClassLoader);

        pluginContext.setTheme(sApplication.getApplicationContext().getApplicationInfo().theme);
        pluginDescriptor.setPluginContext(pluginContext);
        pluginDescriptor.setPluginClassLoader(pluginClassLoader);

        // 使用了openAtlasExtention之后就不需要Public.xml文件了
        // checkPluginPublicXml(pluginDescriptor, pluginRes);

        callPluginApplicationOnCreate(pluginDescriptor);

        LogUtil.d("初始化插件" + pluginDescriptor.getPackageName() + "完成");
      }
    }
  }
 public static String getLabel(PluginDescriptor pd) {
   PackageManager pm = PluginLoader.getApplication().getPackageManager();
   PackageInfo info =
       pm.getPackageArchiveInfo(pd.getInstalledPath(), PackageManager.GET_ACTIVITIES);
   if (info != null) {
     ApplicationInfo appInfo = info.applicationInfo;
     appInfo.sourceDir = pd.getInstalledPath();
     appInfo.publicSourceDir = pd.getInstalledPath();
     String label = null;
     try {
       if (!isMainResId(appInfo.labelRes)) {
         label = pm.getApplicationLabel(appInfo).toString();
       }
     } catch (Resources.NotFoundException e) {
     }
     if (label == null || label.equals(pd.getPackageName())) {
       // 可能设置的lable是来自宿主的资源
       if (pd.getDescription() != null) {
         int id = ResourceUtil.getResourceId(pd.getDescription());
         if (id != 0) {
           // 再宿主中查一次
           try {
             label = PluginLoader.getApplication().getResources().getString(id);
           } catch (Resources.NotFoundException e) {
           }
         }
       }
     }
     if (label != null) {
       return label;
     }
   }
   return pd.getDescription();
 }
 @TargetApi(Build.VERSION_CODES.GINGERBREAD)
 public static Drawable getLogo(PluginDescriptor pd) {
   PackageManager pm = PluginLoader.getApplication().getPackageManager();
   PackageInfo info =
       pm.getPackageArchiveInfo(pd.getInstalledPath(), PackageManager.GET_ACTIVITIES);
   if (info != null) {
     ApplicationInfo appInfo = info.applicationInfo;
     appInfo.sourceDir = pd.getInstalledPath();
     appInfo.publicSourceDir = pd.getInstalledPath();
     Drawable logo = pm.getApplicationLogo(appInfo);
     return logo;
   }
   return null;
 }
  /**
   * 构造插件信息
   *
   * @param
   */
  static void ensurePluginInited(PluginDescriptor pluginDescriptor) {
    if (pluginDescriptor != null) {
      DexClassLoader pluginClassLoader = pluginDescriptor.getPluginClassLoader();
      if (pluginClassLoader == null) {
        LogUtil.e(
            "正在初始化插件"
                + pluginDescriptor.getPackageName()
                + "Resources, DexClassLoader, Context, Application");

        LogUtil.d("是否为独立插件", pluginDescriptor.isStandalone());

        Resources pluginRes = PluginCreator.createPluginResource(sApplication, pluginDescriptor);

        pluginClassLoader =
            PluginCreator.createPluginClassLoader(
                pluginDescriptor.getInstalledPath(),
                pluginDescriptor.isStandalone(),
                pluginDescriptor.getDependencies());
        Context pluginContext =
            PluginCreator.createPluginContext(
                pluginDescriptor, sApplication, pluginRes, pluginClassLoader);

        // 插件Context默认主题设置为插件application主题
        pluginContext.setTheme(pluginDescriptor.getApplicationTheme());
        pluginDescriptor.setPluginContext(pluginContext);
        pluginDescriptor.setPluginClassLoader(pluginClassLoader);

        try {
          ActivityThread.installPackageInfo(getApplicatoin(), pluginDescriptor.getPackageName());
        } catch (ClassNotFoundException e) {
          e.printStackTrace();
        }

        callPluginApplicationOnCreate(pluginDescriptor);

        LogUtil.e("初始化插件" + pluginDescriptor.getPackageName() + "完成");
      }
    }
  }
  /**
   * 安装一个插件
   *
   * @param srcPluginFile
   * @return
   */
  public static synchronized int installPlugin(String srcPluginFile) {
    LogUtil.e("开始安装插件", srcPluginFile);
    if (TextUtils.isEmpty(srcPluginFile) || !new File(srcPluginFile).exists()) {
      return SRC_FILE_NOT_FOUND;
    }

    // 第0步,先将apk复制到宿主程序私有目录,防止在安装过程中文件被篡改
    if (!srcPluginFile.startsWith(sApplication.getCacheDir().getAbsolutePath())) {
      String tempFilePath =
          sApplication.getCacheDir().getAbsolutePath()
              + File.separator
              + System.currentTimeMillis()
              + ".apk";
      if (FileUtil.copyFile(srcPluginFile, tempFilePath)) {
        srcPluginFile = tempFilePath;
      } else {
        LogUtil.e("复制插件文件失败", srcPluginFile, tempFilePath);
        return COPY_FILE_FAIL;
      }
    }

    // 第1步,验证插件APK签名,如果被篡改过,将获取不到证书
    // sApplication.getPackageManager().getPackageArchiveInfo(srcPluginFile,
    // PackageManager.GET_SIGNATURES);
    Signature[] pluginSignatures = PackageVerifyer.collectCertificates(srcPluginFile, false);
    boolean isDebugable =
        (0 != (sApplication.getApplicationInfo().flags & ApplicationInfo.FLAG_DEBUGGABLE));
    if (pluginSignatures == null) {
      LogUtil.e("插件签名验证失败", srcPluginFile);
      new File(srcPluginFile).delete();
      return SIGNATURES_INVALIDATE;
    } else if (NEED_VERIFY_CERT && !isDebugable) {
      // 可选步骤,验证插件APK证书是否和宿主程序证书相同。
      // 证书中存放的是公钥和算法信息,而公钥和私钥是1对1的
      // 公钥相同意味着是同一个作者发布的程序
      Signature[] mainSignatures = null;
      try {
        PackageInfo pkgInfo =
            sApplication
                .getPackageManager()
                .getPackageInfo(sApplication.getPackageName(), PackageManager.GET_SIGNATURES);
        mainSignatures = pkgInfo.signatures;
      } catch (PackageManager.NameNotFoundException e) {
        e.printStackTrace();
      }
      if (!PackageVerifyer.isSignaturesSame(mainSignatures, pluginSignatures)) {
        LogUtil.e("插件证书和宿主证书不一致", srcPluginFile);
        new File(srcPluginFile).delete();
        return VERIFY_SIGNATURES_FAIL;
      }
    }

    // 第2步,解析Manifest,获得插件详情
    PluginDescriptor pluginDescriptor = PluginManifestParser.parseManifest(srcPluginFile);
    if (pluginDescriptor == null || TextUtils.isEmpty(pluginDescriptor.getPackageName())) {
      LogUtil.e("解析插件Manifest文件失败", srcPluginFile);
      new File(srcPluginFile).delete();
      return PARSE_MANIFEST_FAIL;
    }

    PackageInfo packageInfo =
        sApplication
            .getPackageManager()
            .getPackageArchiveInfo(srcPluginFile, PackageManager.GET_GIDS);
    if (packageInfo != null) {
      pluginDescriptor.setApplicationTheme(packageInfo.applicationInfo.theme);
      pluginDescriptor.setApplicationIcon(packageInfo.applicationInfo.icon);
      pluginDescriptor.setApplicationLogo(packageInfo.applicationInfo.logo);
    }

    boolean isNeedPending = false;
    // 第3步,检查插件是否已经存在,若存在删除旧的
    PluginDescriptor oldPluginDescriptor =
        getPluginDescriptorByPluginId(pluginDescriptor.getPackageName());
    if (oldPluginDescriptor != null) {
      LogUtil.e(
          "已安装过,安装路径为",
          oldPluginDescriptor.getInstalledPath(),
          oldPluginDescriptor.getVersion(),
          pluginDescriptor.getVersion());

      // 检查插件是否已经加载
      if (oldPluginDescriptor.getPluginContext() != null) {
        if (!oldPluginDescriptor.getVersion().equals(pluginDescriptor.getVersion())) {
          LogUtil.e("旧版插件已经加载, 且新版插件和旧版插件版本不同,进入pending状态,新版插件将在安装后进程重启再生效");
          isNeedPending = true;
        } else {
          LogUtil.e("旧版插件已经加载, 且新版插件和旧版插件版本相同,拒绝安装");
          new File(srcPluginFile).delete();
          return FAIL_BECAUSE_HAS_LOADED;
        }
      } else {
        LogUtil.e("旧版插件还未加载,忽略版本,直接删除旧版,尝试安装新版");
        remove(oldPluginDescriptor.getPackageName());
      }
    }

    // 第4步骤,复制插件到插件目录
    String destApkPath =
        pluginManager.genInstallPath(
            pluginDescriptor.getPackageName(), pluginDescriptor.getVersion());
    boolean isCopySuccess = FileUtil.copyFile(srcPluginFile, destApkPath);

    if (!isCopySuccess) {

      LogUtil.e("复制插件到安装目录失败", srcPluginFile);
      // 删掉临时文件
      new File(srcPluginFile).delete();
      return COPY_FILE_FAIL;
    } else {

      // 第5步,先解压so到临时目录,再从临时目录复制到插件so目录。 在构造插件Dexclassloader的时候,会使用这个so目录作为参数
      File apkParent = new File(destApkPath).getParentFile();
      File tempSoDir = new File(apkParent, "temp");
      Set<String> soList = FileUtil.unZipSo(srcPluginFile, tempSoDir);
      if (soList != null) {
        for (String soName : soList) {
          FileUtil.copySo(tempSoDir, soName, apkParent.getAbsolutePath());
        }
        // 删掉临时文件
        FileUtil.deleteAll(tempSoDir);
      }

      // 第6步 添加到已安装插件列表
      pluginDescriptor.setInstalledPath(destApkPath);
      boolean isInstallSuccess = false;
      if (!isNeedPending) {
        isInstallSuccess = pluginManager.addOrReplace(pluginDescriptor);
      } else {
        isInstallSuccess = pluginManager.pending(pluginDescriptor);
      }
      // 删掉临时文件
      new File(srcPluginFile).delete();

      if (!isInstallSuccess) {
        LogUtil.e("安装插件失败", srcPluginFile);

        new File(destApkPath).delete();

        return INSTALL_FAIL;
      } else {
        // 通过创建classloader来触发dexopt,但不加载
        LogUtil.d("正在进行DEXOPT...", pluginDescriptor.getInstalledPath());
        FileUtil.deleteAll(new File(apkParent, "dalvik-cache"));
        PluginCreator.createPluginClassLoader(
            pluginDescriptor.getInstalledPath(), pluginDescriptor.isStandalone(), null);
        LogUtil.d("DEXOPT完毕");

        if (!isNeedPending) {
          LocalServiceManager.registerService(pluginDescriptor);
        }

        changeListener.onPluginInstalled(
            pluginDescriptor.getPackageName(), pluginDescriptor.getVersion());
        LogUtil.e("安装插件成功," + (isNeedPending ? " 重启进程生效" : " 立即生效"), destApkPath);

        return SUCCESS;
      }
    }
  }
  /**
   * 安装一个插件
   *
   * @param srcPluginFile
   * @return
   */
  public static synchronized int installPlugin(String srcPluginFile) {
    LogUtil.d("开始安装插件", srcPluginFile);
    if (TextUtils.isEmpty(srcPluginFile) || !new File(srcPluginFile).exists()) {
      return SRC_FILE_NOT_FOUND;
    }

    // 第0步,先将apk复制到宿主程序私有目录,防止在安装过程中文件被篡改
    if (!srcPluginFile.startsWith(sApplication.getCacheDir().getAbsolutePath())) {
      String tempFilePath =
          sApplication.getCacheDir().getAbsolutePath()
              + File.separator
              + System.currentTimeMillis()
              + ".apk";
      if (FileUtil.copyFile(srcPluginFile, tempFilePath)) {
        srcPluginFile = tempFilePath;
      } else {
        LogUtil.e("复制插件文件失败失败", srcPluginFile, tempFilePath);
        return COPY_FILE_FAIL;
      }
    }

    // 第1步,验证插件APK签名,如果被篡改过,将获取不到证书
    // sApplication.getPackageManager().getPackageArchiveInfo(srcPluginFile,
    // PackageManager.GET_SIGNATURES);
    Signature[] pluginSignatures = PackageVerifyer.collectCertificates(srcPluginFile, false);
    boolean isDebugable =
        (0 != (sApplication.getApplicationInfo().flags & ApplicationInfo.FLAG_DEBUGGABLE));
    if (pluginSignatures == null) {
      LogUtil.e("插件签名验证失败", srcPluginFile);
      new File(srcPluginFile).delete();
      return SIGNATURES_INVALIDATE;
    } else if (NEED_VERIFY_CERT && !isDebugable) {
      // 可选步骤,验证插件APK证书是否和宿主程序证书相同。
      // 证书中存放的是公钥和算法信息,而公钥和私钥是1对1的
      // 公钥相同意味着是同一个作者发布的程序
      Signature[] mainSignatures = null;
      try {
        PackageInfo pkgInfo =
            sApplication
                .getPackageManager()
                .getPackageInfo(sApplication.getPackageName(), PackageManager.GET_SIGNATURES);
        mainSignatures = pkgInfo.signatures;
      } catch (PackageManager.NameNotFoundException e) {
        e.printStackTrace();
      }
      if (!PackageVerifyer.isSignaturesSame(mainSignatures, pluginSignatures)) {
        LogUtil.e("插件证书和宿主证书不一致", srcPluginFile);
        new File(srcPluginFile).delete();
        return VERIFY_SIGNATURES_FAIL;
      }
    }

    // 第2步,解析Manifest,获得插件详情
    PluginDescriptor pluginDescriptor = ManifestParser.parseManifest(srcPluginFile);
    if (pluginDescriptor == null || TextUtils.isEmpty(pluginDescriptor.getPackageName())) {
      LogUtil.e("解析插件Manifest文件失败", srcPluginFile);
      new File(srcPluginFile).delete();
      return PARSE_MANIFEST_FAIL;
    }

    PackageInfo packageInfo =
        sApplication
            .getPackageManager()
            .getPackageArchiveInfo(srcPluginFile, PackageManager.GET_GIDS);
    pluginDescriptor.setApplicationTheme(packageInfo.applicationInfo.theme);
    pluginDescriptor.setApplicationIcon(packageInfo.applicationInfo.icon);
    pluginDescriptor.setApplicationLogo(packageInfo.applicationInfo.logo);

    // 第3步,检查插件是否已经存在,若存在删除旧的
    PluginDescriptor oldPluginDescriptor =
        getPluginDescriptorByPluginId(pluginDescriptor.getPackageName());
    if (oldPluginDescriptor != null) {
      LogUtil.e("已安装过,先删除旧版本", pluginDescriptor.getInstalledPath());
      remove(pluginDescriptor.getPackageName());
    }

    // 第4步骤,复制插件到插件目录
    String destPluginFile =
        pluginManager.genInstallPath(
            pluginDescriptor.getPackageName(), pluginDescriptor.getVersion());
    boolean isCopySuccess = FileUtil.copyFile(srcPluginFile, destPluginFile);

    if (!isCopySuccess) {

      LogUtil.d("复制插件到安装目录失败", srcPluginFile);
      new File(srcPluginFile).delete();
      return COPY_FILE_FAIL;
    } else {

      // 第5步,复制插件so到插件so目录, 在构造插件Dexclassloader的时候,会使用这个so目录作为参数
      File tempDir = new File(new File(destPluginFile).getParentFile(), "temp");
      Set<String> soList = FileUtil.unZipSo(srcPluginFile, tempDir);
      if (soList != null) {
        for (String soName : soList) {
          FileUtil.copySo(
              tempDir, soName, new File(destPluginFile).getParent() + File.separator + "lib");
        }
        FileUtil.deleteAll(tempDir);
      }

      // 第6步 添加到已安装插件列表
      pluginDescriptor.setInstalledPath(destPluginFile);
      boolean isInstallSuccess = pluginManager.addOrReplace(pluginDescriptor);

      new File(srcPluginFile).delete();

      if (!isInstallSuccess) {
        LogUtil.d("安装插件失败", srcPluginFile);
        return INSTALL_FAIL;
      } else {
        changeListener.onPluginInstalled(
            pluginDescriptor.getPackageName(), pluginDescriptor.getVersion());
        LogUtil.d("安装插件成功", destPluginFile);
        return SUCCESS;
      }
    }
  }