Example #1
0
PhpFunc::PhpFunc(const folly::dynamic& d,
                 const fbstring& className) :
    m_name(d["name"].asString()),
    m_className(className),
    m_func(d),
    m_desc(getFollyDynamicDefaultString(d, "desc", "")),
    m_returnRef(d.getDefault("ref", "false") == "true"),
    m_returnKindOf(KindOfNull),
    m_returnCppType("void"),
    m_returnPhpType("void"),
    m_minNumParams(0),
    m_numTypeChecks(0) {
  auto returnIt = d.find("return");
  if (returnIt != d.items().end()) {
    auto retNode = returnIt->second;
    auto typeIt = retNode.find("type");
    if (typeIt != retNode.items().end()) {
      auto type = typeIt->second;
      if ((type.isString()) && (type != "void") && (type != "null")) {
        m_returnKindOf = m_returnRef ? KindOfRef : kindOfFromDynamic(type);
        m_returnCppType = typeString(type, true);
        m_returnPhpType = phpTypeFromDataType(m_returnKindOf);
      }
    }
    m_returnDesc = getFollyDynamicDefaultString(retNode, "desc", "");
  }

  auto args = d.find("args");
  if (args == d.items().end() || !args->second.isArray()) {
    throw std::logic_error(
      folly::format("'{0}' must have an array field 'args'", name()).str()
    );
  }
  auto ret = d.find("return");
  if (ret == d.items().end() || !ret->second.isObject() ||
      ret->second.find("type") == ret->second.items().end()) {
    throw std::logic_error(
      folly::format("'{0}' must have an array field 'return', which must have "
                    "a string field 'type'", name()).str()
    );
  }

  bool magic = isMagicMethod();
  for (auto &p : args->second) {
    PhpParam param(p, magic);
    m_params.push_back(param);
    if (!param.hasDefault()) {
      ++m_minNumParams;
    }
    if (param.isCheckedType()) {
      ++m_numTypeChecks;
    }
  }

  m_flags = parseFlags(m_func["flags"]);
}
Example #2
0
void Scheduler::startSurface(
    SurfaceId surfaceId,
    const std::string &moduleName,
    const folly::dynamic &initialProps,
    const LayoutConstraints &layoutConstraints,
    const LayoutContext &layoutContext) {
  std::lock_guard<std::mutex> lock(mutex_);

  auto shadowTree =
      std::make_unique<ShadowTree>(surfaceId, layoutConstraints, layoutContext);
  shadowTree->setDelegate(this);
  shadowTreeRegistry_.emplace(surfaceId, std::move(shadowTree));

#ifndef ANDROID

  // TODO: Is this an ok place to do this?
  auto serializedCommands = initialProps.find("serializedCommands");
  if (serializedCommands != initialProps.items().end()) {
    auto tree = TemplateRenderer::buildShadowTree(serializedCommands->second.asString(), surfaceId, folly::dynamic::object(), *componentDescriptorRegistry_);

    uiManagerDidFinishTransactionWithoutLock(surfaceId, std::make_shared<SharedShadowNodeList>(SharedShadowNodeList {tree}));
    // TODO: hydrate rather than replace
    uiManager_->startSurface(surfaceId, moduleName, initialProps);
  } else {
    uiManager_->startSurface(surfaceId, moduleName, initialProps);
  }
#endif
}
Example #3
0
bool PhpConst::parseType(const folly::dynamic& cns) {
  auto it = cns.find("type");
  if (it != cns.items().end()) {
    m_kindOf = kindOfFromDynamic(it->second);
    m_cppType = typeString(it->second, false);
    return true;
  }
  return false;
}
Example #4
0
PhpClass::PhpClass(const folly::dynamic &c) :
  m_class(c),
  m_idlName(c["name"].asString()),
  m_phpName(toPhpName(m_idlName)),
  m_cppName(toCppName(m_idlName)),
  m_flags(parseFlags(m_class["flags"])),
  m_desc(getFollyDynamicDefaultString(c, "desc", "")) {

  auto ifacesIt = m_class.find("ifaces");
  if (ifacesIt != m_class.items().end()) {
    auto ifaces = ifacesIt->second;
    if (!ifaces.isArray()) {
      throw std::logic_error(
        folly::format("Class {0}.ifaces field must be an array",
          m_idlName).str()
      );
    }
    for (auto &interface : ifaces) {
      m_ifaces.push_back(interface.asString());
    }
  }

  for (auto const& f : c["funcs"]) {
    PhpFunc func(f, getCppName());
    m_methods.push_back(func);
  }

  if (c.find("consts") != c.items().end()) {
    for (auto const& cns : c["consts"]) {
      PhpConst cons(cns, getCppName());
      m_constants.push_back(cons);
    }
  }

  if (c.find("properties") != c.items().end()) {
    for (auto const& prp : c["properties"]) {
      PhpProp prop(prp, getCppName());
      m_properties.push_back(prop);
    }
  }
}
Example #5
0
bool PhpConst::inferType(const folly::dynamic& cns) {
  auto it = cns.find("value");
  if (it != cns.items().end()) {
    m_kindOf = kindOfFromValue(it->second);
    auto typeIt = g_typeMap.find((int)m_kindOf);
    if (typeIt != g_typeMap.end()) {
      m_cppType = typeIt->second;
      return true;
    }
  }
  return false;
}
Example #6
0
static fbstring getFollyDynamicDefaultString(const folly::dynamic& d,
                                             const fbstring& key,
                                             const fbstring& def) {
  auto it = d.find(key);
  if (it == d.items().end()) {
    return def;
  }
  auto val = it->second;
  if (val.isNull()) {
    return def;
  }
  return val.asString();
}
Example #7
0
AclEntryFields AclEntryFields::fromFollyDynamic(
    const folly::dynamic& aclEntryJson) {
  AclEntryFields aclEntry(AclEntryID(aclEntryJson[kId].asInt()));
  if (aclEntryJson.find(kSrcIp) != aclEntryJson.items().end()) {
    aclEntry.srcIp = IPAddress::createNetwork(
      aclEntryJson[kSrcIp].asString());
  }
  if (aclEntryJson.find(kDstIp) != aclEntryJson.items().end()) {
    aclEntry.dstIp = IPAddress::createNetwork(
      aclEntryJson[kDstIp].asString());
  }
  if (aclEntry.srcIp.first && aclEntry.dstIp.first &&
      aclEntry.srcIp.first.isV4() != aclEntry.dstIp.first.isV4()) {
    throw FbossError(
      "Unmatched ACL IP versions ",
      aclEntryJson[kSrcIp].asString(),
      " vs ",
      aclEntryJson[kDstIp].asString()
    );
  }
  if (aclEntryJson.find(kL4SrcPort) != aclEntryJson.items().end()) {
    aclEntry.l4SrcPort = aclEntryJson[kL4SrcPort].asInt();
  }
  if (aclEntryJson.find(kL4DstPort) != aclEntryJson.items().end()) {
    aclEntry.l4DstPort = aclEntryJson[kL4DstPort].asInt();
  }
  if (aclEntryJson.find(kProto) != aclEntryJson.items().end()) {
    aclEntry.proto = aclEntryJson[kProto].asInt();
  }
  if (aclEntryJson.find(kTcpFlags) != aclEntryJson.items().end()) {
    aclEntry.tcpFlags = aclEntryJson[kTcpFlags].asInt();
  }
  if (aclEntryJson.find(kTcpFlagsMask) != aclEntryJson.items().end()) {
    aclEntry.tcpFlagsMask = aclEntryJson[kTcpFlagsMask].asInt();
  }
  auto itr_action = cfg::_AclAction_NAMES_TO_VALUES.find(
    aclEntryJson[kAction].asString().c_str());
  if (itr_action == cfg::_AclAction_NAMES_TO_VALUES.end()) {
    throw FbossError(
      "Unsupported ACL action ", aclEntryJson[kAction].asString());
  }
  aclEntry.action = cfg::AclAction(itr_action->second);
  return aclEntry;
}
Example #8
0
SwitchStateFields
SwitchStateFields::fromFollyDynamic(const folly::dynamic& swJson) {
  SwitchStateFields switchState;
  switchState.interfaces = InterfaceMap::fromFollyDynamic(
        swJson[kInterfaces]);
  switchState.ports = PortMap::fromFollyDynamic(swJson[kPorts]);
  switchState.vlans = VlanMap::fromFollyDynamic(swJson[kVlans]);
  switchState.routeTables = RouteTableMap::fromFollyDynamic(
      swJson[kRouteTables]);
  switchState.acls = AclMap::fromFollyDynamic(swJson[kAcls]);
  if (swJson.count(kSflowCollectors) > 0) {
    switchState.sFlowCollectors = SflowCollectorMap::fromFollyDynamic(
      swJson[kSflowCollectors]);
  }
  switchState.defaultVlan = VlanID(swJson[kDefaultVlan].asInt());
  if (swJson.find(kControlPlane) != swJson.items().end()) {
    switchState.controlPlane = ControlPlane::fromFollyDynamic(
      swJson[kControlPlane]);
  }
  //TODO verify that created state here is internally consistent t4155406
  return switchState;
}
Example #9
0
PhpFunc::PhpFunc(const folly::dynamic& d,
                 const fbstring& className) :
    m_idlName(d["name"].asString()),
    m_phpName(toPhpName(m_idlName)),
    m_cppName(toCppName(m_idlName)),
    m_className(className),
    m_func(d),
    m_desc(getFollyDynamicDefaultString(d, "desc", "")),
    m_returnRef(d.getDefault("ref", "false") == "true"),
    m_returnKindOf(KindOfNull),
    m_returnCppType("void"),
    m_returnPhpType("void"),
    m_minNumParams(0),
    m_numTypeChecks(0) {

  if (isMethod() &&
      m_idlName.find_last_of(NAMESPACE_STRING) != std::string::npos) {
    throw std::logic_error(
      folly::format("'{0}' is a method and cannot have a namespace in its name",
                    m_idlName).str()
    );
  }
  auto returnIt = d.find("return");
  if (returnIt != d.items().end()) {
    auto retNode = returnIt->second;
    auto typeIt = retNode.find("type");
    if (typeIt != retNode.items().end()) {
      auto type = typeIt->second;
      if ((type.isString()) && (type != "void") && (type != "null")) {
        m_returnKindOf = m_returnRef ? KindOfRef : kindOfFromDynamic(type);
        m_returnCppType = typeString(type, true);
        m_returnPhpType = phpTypeFromDataType(m_returnKindOf);
      }
    }
    m_returnDesc = getFollyDynamicDefaultString(retNode, "desc", "");
  }

  auto args = d.find("args");
  if (args == d.items().end() || !args->second.isArray()) {
    throw std::logic_error(
      folly::format("'{0}' must have an array field 'args'", m_idlName).str()
    );
  }
  auto ret = d.find("return");
  if (ret == d.items().end() || !ret->second.isObject() ||
      ret->second.find("type") == ret->second.items().end()) {
    throw std::logic_error(
      folly::format("'{0}' must have an array field 'return', which must have "
                    "a string field 'type'", m_idlName).str()
    );
  }

  bool magic = isMagicMethod();

  m_flags = parseFlags(m_func["flags"]);

  ParamMode paramMode = ParamMode::CoerceAndCall;
  if (m_flags & ParamCoerceModeNull) {
    paramMode = ParamMode::ZendNull;
  } else if (m_flags & ParamCoerceModeFalse) {
    paramMode = ParamMode::ZendFalse;
  }

  for (auto &p : args->second) {
    PhpParam param(p, magic, paramMode);
    m_params.push_back(param);
    if (!param.hasDefault()) {
      ++m_minNumParams;
    }
    if (param.isCheckedType()) {
      ++m_numTypeChecks;
    }
  }
}
Example #10
0
PhpFunc PhpFunc::fromDynamic(const folly::dynamic& d,
                             const fbstring& className) {
  // Better at least have a name
  auto name = d["name"].asString();
  auto args = d.find("args");
  auto flags = d.find("flags");
  auto ret = d.find("return");
  if (args == d.items().end() || !args->second.isArray()) {
    throw std::logic_error(
      folly::format("'{0}' must have an array field 'args'", name).str()
    );
  }
  if (flags == d.items().end() || !flags->second.isArray()) {
    throw std::logic_error(
      folly::format("'{0}' must have an array field 'flags'", name).str()
    );
  }
  if (ret == d.items().end() || !ret->second.isObject() ||
      ret->second.find("type") == ret->second.items().end()) {
    throw std::logic_error(
      folly::format("'{0}' must have an array field 'return', which must have "
                    "a string field 'type'", name).str()
    );
  }

  auto areVarargs = [](const fbstring& str) {
    return (str == "VariableArguments" ||
            str == "RefVariableArguments" ||
            str == "MixedVariableArguments");
  };

  fbvector<PhpParam> params;
  try {
    params = std::move(folly::convertTo<fbvector<PhpParam>>(args->second));
  } catch (const std::exception& exc) {
    throw std::logic_error(
      folly::format("'{0}' has an arg with either 'name' or 'type' field "
                    "missing", name).str()
    );
  }
  if (name == "__get" ||
      name == "__set" ||
      name == "__isset" ||
      name == "__unset" ||
      name == "__call") {
    for (auto& param : params) {
      param.cppType = "HPHP::Variant";
    }
  }

  auto refIt = d.find("ref");
  bool ref = (refIt != d.items().end() && refIt->second.asString() == "true");

  PhpFunc retval;
  retval.name = name;
  retval.className = className;
  retval.returnCppType = typeString(ret->second["type"], true);
  retval.returnByRef = ref;
  retval.params = params;
  retval.isVarargs = anyFlags(areVarargs, flags->second);
  retval.isStatic = false;

  if (!className.empty()) {
    auto areStatic = [](const fbstring& str) {
      return str == "IsStatic";
    };

    retval.isStatic = anyFlags(areStatic, flags->second);
  }
  retval.initComputedProps();
  return retval;
}
Example #11
0
/*
 * Initializes list of classes that are reachable via reflection, and calls
 * or from code.
 *
 * These include:
 *  - Classes used in the manifest (e.g. activities, services, etc)
 *  - View or Fragment classes used in layouts
 *  - Classes that are in certain packages (specified in the reflected_packages
 *    section of the config) and classes that extend from them
 *  - Classes marked with special annotations (keep_annotations in config)
 *  - Classes reachable from native libraries
 */
static void init_permanently_reachable_classes(const Scope& scope, folly::dynamic& config, const std::vector<KeepRule>& proguard_rules) {

  std::string apk_dir;
  std::vector<std::string> reflected_package_names;

  auto config_apk_dir = config.find("apk_dir");
  if (config_apk_dir != config.items().end()) {
    apk_dir = toStdString(config_apk_dir->second.asString());
  }

  auto config_reflected_package_names = config.find("reflected_packages");
  if (config_reflected_package_names != config.items().end()) {
    for (auto config_pkg_name : config_reflected_package_names->second) {
      std::string pkg_name = toStdString(config_pkg_name.asString());
      reflected_package_names.push_back(pkg_name);
    }
  }

  std::unordered_set<DexType*> keep_annotations;
  auto config_keep_annotations = config.find("keep_annotations");
  if (config_keep_annotations != config.items().end()) {
    for (auto const& config_anno_name : config_keep_annotations->second) {
      std::string anno_name = toStdString(config_anno_name.asString());
      DexType* anno = DexType::get_type(anno_name.c_str());
      if (anno) keep_annotations.insert(anno);
    }
  }
  keep_annotated_classes(scope, keep_annotations);

  std::vector<std::string> keep_pkgs;
  auto config_keep_packages = config.find("keep_packages");
  if (config_keep_packages != config.items().end()) {
    for (auto const& config_pkg : config_keep_packages->second) {
      auto pkg_name = toStdString(config_pkg.asString());
      keep_pkgs.push_back(pkg_name);
    }
  }
  keep_packages(scope, keep_pkgs);

  if (apk_dir.size()) {
    // Classes present in manifest
    std::string manifest = apk_dir + std::string("/AndroidManifest.xml");
    for (std::string classname : get_manifest_classes(manifest)) {
      mark_reachable_by_classname(classname, false);
    }

    // Classes present in XML layouts
    for (std::string classname : get_layout_classes(apk_dir)) {
      mark_reachable_by_classname(classname, false);
    }

    // Classnames present in native libraries (lib/*/*.so)
    for (std::string classname : get_native_classes(apk_dir)) {
      mark_reachable_by_classname(classname, false);
    }
  }

  std::unordered_set<DexClass*> reflected_package_classes;
  for (auto clazz : scope) {
    const char* cname = clazz->get_type()->get_name()->c_str();
    for (auto pkg : reflected_package_names) {
      if (starts_with(cname, pkg.c_str())) {
        reflected_package_classes.insert(clazz);
        continue;
      }
    }
  }
  for (auto clazz : scope) {
    if (in_reflected_pkg(clazz, reflected_package_classes)) {
      reflected_package_classes.insert(clazz);
      /* Note:
       * Some of these are by string, others by type
       * but we have no way in the config to distinguish
       * them currently.  So, we mark with the most
       * conservative sense here.
       */
      mark_reachable_by_classname(clazz, false);
    }
  }

  /* Do only keep class rules for now.
   * '*' and '**' rules are skipped,
   * because those are matching on something else,
   * which we haven't implemented yet.
   * Rules can be "*" or "**" on classname and match
   * on some other attribute. We don't match against
   * all attributes at once, so this prevents us
   * from matching everything.
   */
  std::vector<std::string> cls_patterns;
  for (auto const& r : proguard_rules) {
    if (r.classname != nullptr &&
        r.class_type == keeprules::ClassType::CLASS &&
          strlen(r.classname) > 2) {
      std::string cls_pattern(r.classname);
      std::replace(cls_pattern.begin(), cls_pattern.end(), '.', '/');
      auto prep_pat = 'L' + cls_pattern;
      TRACE(PGR, 1, "adding pattern %s \n", prep_pat.c_str());
      cls_patterns.push_back(prep_pat);
    }
  }
  size_t pg_marked_classes = 0;
  for (auto clazz : scope) {
    auto cname = clazz->get_type()->get_name()->c_str();
    auto cls_len = strlen(cname);
    for (auto const& pat : cls_patterns) {
        int pat_len = pat.size();
        if (type_matches(pat.c_str(), cname, pat_len, cls_len)) {
          mark_reachable_directly(clazz);
          TRACE(PGR, 2, "matched cls %s against pattern %s \n", cname, pat.c_str());
          pg_marked_classes++;
          break;
      }
    }
  }
  TRACE(PGR, 1, "matched on %lu classes with CLASS KEEP proguard rules \n",
      pg_marked_classes);
}