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"]); }
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 }
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; }
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); } } }
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; }
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(); }
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; }
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; }
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; } } }
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; }
/* * 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); }