0%

Movian 插件加载分析

分析源文件 src/plugins.c

install

plugin_install -> plugin_load -> ecmascript_plugin_load

plugin_load

解析 plugin.json 文件

//plugin.json 路径
snprintf(ctrlfile, sizeof(ctrlfile), "%s/plugin.json", url);

// 读取文件内容
if((b = fa_load(ctrlfile,
                FA_LOAD_ERRBUF(errbuf2, sizeof(errbuf2)),
                NULL)) == NULL) {
  snprintf(errbuf, errlen, "Unable to load %s -- %s", ctrlfile, errbuf2);
  return -1;
}

// 解析 json 文件
ctrl = htsmsg_json_deserialize2(buf_cstr(b), errbuf, errlen);

// 获取数据
const char *type = htsmsg_get_str(ctrl, "type");
const char *id   = htsmsg_get_str(ctrl, "id");
const char *version = htsmsg_get_str(ctrl, "version");
const char *file = htsmsg_get_str(ctrl, "file");

//js 文件路径
snprintf(fullpath, sizeof(fullpath), "%s/%s", url, file);

int version = htsmsg_get_u32_or_default(ctrl, "apiversion", 1);

// 打开 js 文件
hts_mutex_unlock(&plugin_mutex);
r = ecmascript_plugin_load(id, fullpath, errbuf, errlen, version,
                           buf_cstr(b), pflags);
hts_mutex_lock(&plugin_mutex);

scmascript_plugin_load

int
ecmascript_plugin_load(const char *id, const char *url,
                       char *errbuf, size_t errlen,
                       int version, const char *manifest,
                       int flags)
{
  char storage[PATH_MAX];

  snprintf(storage, sizeof(storage),
           "%s/plugins/%s", gconf.persistent_path, id);

  es_context_t *ec = es_context_create(id, flags | ECMASCRIPT_PLUGIN,
                                       url, storage);

  duk_context *ctx = es_context_begin(ec);

  duk_push_global_object(ctx);

  int plugin_obj_idx = duk_push_object(ctx);

  duk_push_string(ctx, id);
  duk_put_prop_string(ctx, plugin_obj_idx, "id");

  duk_push_string(ctx, url);
  duk_put_prop_string(ctx, plugin_obj_idx, "url");

  duk_push_string(ctx, manifest);
  duk_put_prop_string(ctx, plugin_obj_idx, "manifest");

  duk_push_int(ctx, version);
  duk_put_prop_string(ctx, plugin_obj_idx, "apiversion");
  if(ec->ec_path) {
    duk_push_string(ctx, ec->ec_path);
    duk_put_prop_string(ctx, plugin_obj_idx, "path");
  }

  //Plugin object {"id": , "url": , "manifest": , "apiversion": , "path": }
  duk_put_prop_string(ctx, -2, "Plugin");
  duk_pop(ctx);

  if(version == 1) {

    int64_t ts0 = arch_get_ts();

    // 根据文件及路径编译为函数
    if(es_load_and_compile(ec, "dataroot://res/ecmascript/legacy/api-v1.js",
                           ctx))
      goto bad;

    int64_t ts1 = arch_get_ts();

    // 执行函数
    if(duk_pcall(ctx, 0)) {
      es_dump_err(ctx);
      goto bad;
    }

    int64_t ts2 = arch_get_ts();

    //xx.js 编译
    if(es_load_and_compile(ec, url, ctx)) {
      duk_pop(ctx);
      goto bad;
    }

    int64_t ts3 = arch_get_ts();

    duk_swap_top(ctx, 0);
    // 执行
    if(duk_pcall_method(ctx, 0))
      es_dump_err(ctx);

    int64_t ts4 = arch_get_ts();

    es_debug(ec, "API v1 emulation: Compile:%dms Exec:%dms",
             ((int)(ts1 - ts0)) / 1000,
             ((int)(ts2 - ts1)) / 1000);

    es_debug(ec, "Plugin main:      Compile:%dms Exec:%dms",
             ((int)(ts3 - ts2)) / 1000,
             ((int)(ts4 - ts3)) / 1000);

  } else {
    es_exec(ec, url, ctx);
  }

 bad:
  es_context_end(ec, 1, ctx);

  es_context_release(ec);

  return 0;
}