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
JSValueRef Value::fromDynamicInner(JSContextRef ctx, const folly::dynamic& obj) {
  switch (obj.type()) {
    // For primitive types (and strings), just create and return an equivalent JSValue
    case folly::dynamic::Type::NULLT:
      return JSC_JSValueMakeNull(ctx);

    case folly::dynamic::Type::BOOL:
      return JSC_JSValueMakeBoolean(ctx, obj.getBool());

    case folly::dynamic::Type::DOUBLE:
      return JSC_JSValueMakeNumber(ctx, obj.getDouble());

    case folly::dynamic::Type::INT64:
      return JSC_JSValueMakeNumber(ctx, obj.asDouble());

    case folly::dynamic::Type::STRING:
      return JSC_JSValueMakeString(ctx, String(ctx, obj.getString().c_str()));

    case folly::dynamic::Type::ARRAY: {
      // Collect JSValue for every element in the array
      JSValueRef vals[obj.size()];
      for (size_t i = 0; i < obj.size(); ++i) {
        vals[i] = fromDynamicInner(ctx, obj[i]);
      }
      // Create a JSArray with the values
      JSValueRef arr = JSC_JSObjectMakeArray(ctx, obj.size(), vals, nullptr);
      return arr;
    }

    case folly::dynamic::Type::OBJECT: {
      // Create an empty object
      JSObjectRef jsObj = JSC_JSObjectMake(ctx, nullptr, nullptr);
      // Create a JSValue for each of the object's children and set them in the object
      for (auto it = obj.items().begin(); it != obj.items().end(); ++it) {
        JSC_JSObjectSetProperty(
          ctx,
          jsObj,
          String(ctx, it->first.asString().c_str()),
          fromDynamicInner(ctx, it->second),
          kJSPropertyAttributeNone,
          nullptr);
      }
      return jsObj;
    }
    default:
      // Assert not reached
      LOG(FATAL) << "Trying to convert a folly object of unsupported type.";
      return JSC_JSValueMakeNull(ctx);
  }
}
ShardSplitter::ShardSplitter(const folly::dynamic& json) {
  if (!json.isObject()) {
    return;
  }

  for (const auto& it : json.items()) {
    if (!it.second.isInt()) {
      LOG(ERROR) << "ShardSplitter: shard_splits value is not an int for "
                 << it.first.asString();
      continue;
    }

    auto splitCnt = it.second.asInt();
    if (splitCnt <= 0) {
      LOG(ERROR) << "ShardSplitter: shard_splits value <= 0 '"
                 << it.first.asString() << "': " << splitCnt;
    } else if (static_cast<size_t>(splitCnt) > kMaxSplits) {
      LOG(ERROR) << "ShardSplitter: shard_splits value > " << kMaxSplits
                 << " '" << it.first.asString() << "': " << splitCnt;
      shardSplits_.emplace(it.first.c_str(), kMaxSplits);
    } else {
      shardSplits_.emplace(it.first.c_str(), splitCnt);
    }
  }
}
void HyperlinkViewManager::UpdateProperties(ShadowNodeBase* nodeToUpdate, const folly::dynamic& reactDiffMap)
{
  auto button = nodeToUpdate->GetView().as<winrt::HyperlinkButton>();
  if (button == nullptr)
    return;

  for (const auto& pair : reactDiffMap.items())
  {
    const std::string& propertyName = pair.first.getString();
    const folly::dynamic& propertyValue = pair.second;

   if (propertyName == "disabled")
   {
      if (propertyValue.isBool())
        button.IsEnabled(!propertyValue.asBool());
   }
   else if (propertyName == "tooltip")
   {
     if (propertyValue.isString())
     {
       winrt::TextBlock tooltip = winrt::TextBlock();
       tooltip.Text(asHstring(propertyValue));
       winrt::ToolTipService::SetToolTip(button, tooltip);
     }
   }
   else if (propertyName == "url")
   {
     winrt::Uri myUri(asHstring(propertyValue));
     button.NavigateUri(myUri);
   }
  }

  Super::UpdateProperties(nodeToUpdate, reactDiffMap);
}
Example #5
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
}
void SwitchViewManager::UpdateProperties(ShadowNodeBase* nodeToUpdate, const folly::dynamic& reactDiffMap)
{
  auto toggleSwitch = nodeToUpdate->GetView().as<winrt::ToggleSwitch>();
  if (toggleSwitch == nullptr)
    return;

  for (const auto& pair : reactDiffMap.items())
  {
    const std::string& propertyName = pair.first.getString();
    const folly::dynamic& propertyValue = pair.second;

   if (propertyName == "disabled")
   {
      if (propertyValue.isBool())
        toggleSwitch.IsEnabled(!propertyValue.asBool());
      else if (pair.second.isNull())
        toggleSwitch.ClearValue(winrt::Control::IsEnabledProperty());
   }
   else if (propertyName == "value")
   {
     if (propertyValue.isBool())
       toggleSwitch.IsOn(propertyValue.asBool());
     else if (pair.second.isNull())
       toggleSwitch.ClearValue(winrt::ToggleSwitch::IsOnProperty());
   }
  }

  Super::UpdateProperties(nodeToUpdate, reactDiffMap);
}
void CheckBoxViewManager::UpdateProperties(ShadowNodeBase* nodeToUpdate, const folly::dynamic& reactDiffMap)
{
  auto checkbox = nodeToUpdate->GetView().as<winrt::CheckBox>();
  if (checkbox == nullptr)
    return;

  for (const auto& pair : reactDiffMap.items())
  {
    const std::string& propertyName = pair.first.getString();
    const folly::dynamic& propertyValue = pair.second;

   if (propertyName == "disabled")
   {
     if (propertyValue.isBool())
       checkbox.IsEnabled(!propertyValue.asBool());
     else if (pair.second.isNull())
       checkbox.ClearValue(winrt::Control::IsEnabledProperty());
   }
   else if (propertyName == "checked")
   {
     if (propertyValue.isBool())
       checkbox.IsChecked(propertyValue.asBool());
     else if (pair.second.isNull())
       checkbox.ClearValue(winrt::Primitives::ToggleButton::IsCheckedProperty());
   }
  }

  Super::UpdateProperties(nodeToUpdate, reactDiffMap);
}
Example #8
0
static Variant dynamic_to_variant(const folly::dynamic& v) {
  switch (v.type()) {
    case folly::dynamic::Type::NULLT:
      return init_null();
    case folly::dynamic::Type::BOOL:
      return v.asBool();
    case folly::dynamic::Type::DOUBLE:
      return v.asDouble();
    case folly::dynamic::Type::INT64:
      return v.asInt();
    case folly::dynamic::Type::STRING:
      return v.data();
    case folly::dynamic::Type::ARRAY:
    case folly::dynamic::Type::OBJECT:
      ArrayInit arr_init(v.size(), ArrayInit::Mixed{});
      for (auto& item : v.items()) {
        arr_init.add(dynamic_to_variant(item.first),
                dynamic_to_variant(item.second));
      }
      Array ret = arr_init.toArray();
      // Sort the array since folly::dynamic has a tendency to iterate from
      // back to front. This way a var_dump of the array, for example, looks
      // ordered.
      ret.sort(Array::SortNaturalAscending, true, false);
      return ret;
  }
  not_reached();
}
Example #9
0
bool ini_on_update(const folly::dynamic& value,
                   std::map<std::string, std::string>& p) {
  INI_ASSERT_ARR(value);
  for (auto& pair : value.items()) {
    p[pair.first.data()] = pair.second.data();
  }
  return true;
}
RouteNextHopsMulti
RouteNextHopsMulti::fromFollyDynamic(const folly::dynamic& json) {
  RouteNextHopsMulti nh;
  for (const auto& pair : json.items()) {
    nh.update(ClientID(pair.first.asInt()),
              RouteNextHopEntry::fromFollyDynamic(pair.second));
  }
  return nh;
}
Example #11
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 #12
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 #13
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 #14
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();
}
SharedShadowNode UITemplateProcessor::buildShadowTree(
    const std::string &jsonStr,
    Tag rootTag,
    const folly::dynamic &params,
    const ComponentDescriptorRegistry &componentDescriptorRegistry,
    const NativeModuleRegistry &nativeModuleRegistry,
    const std::shared_ptr<const ReactNativeConfig> reactNativeConfig) {
  LOG(INFO)
      << "(strt) UITemplateProcessor inject hardcoded 'server rendered' view tree";

  std::string content = jsonStr;
  for (const auto &param : params.items()) {
    const auto &key = param.first.asString();
    size_t start_pos = content.find(key);
    if (start_pos != std::string::npos) {
      content.replace(start_pos, key.length(), param.second.asString());
    }
  }
  auto parsed = folly::parseJson(content);
  auto commands = parsed["commands"];
  std::vector<SharedShadowNode> nodes(commands.size() * 2);
  std::vector<folly::dynamic> registers(32);
  for (const auto &command : commands) {
    try {
      if (DEBUG_FLY) {
        LOG(INFO) << "try to run command " << folly::toJson(command);
      }
      auto ret = runCommand(
          command,
          rootTag,
          nodes,
          registers,
          componentDescriptorRegistry,
          nativeModuleRegistry,
          reactNativeConfig);
      if (ret != nullptr) {
        return ret;
      }
    } catch (const std::exception &e) {
      LOG(ERROR) << "   >>> Exception <<<    running previous command '"
                 << folly::toJson(command) << "': '" << e.what() << "'";
    }
  }
  LOG(ERROR) << "react ui template missing returnRoot command :(";
  throw std::runtime_error(
      "Missing returnRoot command in template content:\n" + content);
  return SharedShadowNode{};
}
 LocationObserverOptions(const folly::dynamic& options)
 {
   if (!options.empty())
   {
     for (auto& opt : options.items())
     {
       if (opt.first == "timeout")
         timeout = opt.second.asDouble();
       else if (opt.first == "maximumAge")
         maxAge = opt.second.asDouble();
       else if (opt.first == "enableHighAccuracy")
         highAccuracy = opt.second.asBool();
       else if (opt.first == "distanceFilter")
         distanceFilter = opt.second.asDouble();
     }
   }
 }
Example #17
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 #18
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 #19
0
static Variant dynamic_to_variant(const folly::dynamic& v) {
    switch (v.type()) {
    case folly::dynamic::Type::NULLT:
        return init_null_variant;
    case folly::dynamic::Type::BOOL:
        return v.asBool();
    case folly::dynamic::Type::DOUBLE:
        return v.asDouble();
    case folly::dynamic::Type::INT64:
        return v.asInt();
    case folly::dynamic::Type::STRING:
        return v.data();
    case folly::dynamic::Type::ARRAY:
    case folly::dynamic::Type::OBJECT:
        ArrayInit ret(v.size(), ArrayInit::Mixed{});
        for (auto& item : v.items()) {
            ret.add(dynamic_to_variant(item.first),
                    dynamic_to_variant(item.second));
        }
        return ret.toArray();
    }
    not_reached();
}
Example #20
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 #21
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 #22
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);
}
ReadableNativeMapKeySetIterator::ReadableNativeMapKeySetIterator(const folly::dynamic& map)
  : iter_(map.items().begin())
  , map_(map) {}
Example #24
0
std::shared_ptr<ClientPool>
PoolFactory::parsePool(const std::string& name, const folly::dynamic& json) {
  auto seenPoolIt = pools_.find(name);
  if (seenPoolIt != pools_.end()) {
    return seenPoolIt->second;
  }

  if (json.isString()) {
    // get the pool from ConfigApi
    std::string jsonStr;
    checkLogic(configApi_.get(ConfigType::Pool, name, jsonStr),
               "Can not read pool: {}", name);
    return parsePool(name, parseJsonString(jsonStr));
  } else {
    // one day we may add inheriting from local pool
    if (auto jinherit = json.get_ptr("inherit")) {
      checkLogic(jinherit->isString(),
                 "Pool {}: inherit is not a string", name);
      auto path = jinherit->stringPiece().str();
      std::string jsonStr;
      checkLogic(configApi_.get(ConfigType::Pool, path, jsonStr),
                 "Can not read pool from: {}", path);
      auto newJson = parseJsonString(jsonStr);
      for (auto& it : json.items()) {
        newJson.insert(it.first, it.second);
      }
      newJson.erase("inherit");
      return parsePool(name, newJson);
    }
  }

  // pool_locality
  std::chrono::milliseconds timeout{opts_.server_timeout_ms};
  if (auto jlocality = json.get_ptr("pool_locality")) {
    if (!jlocality->isString()) {
      MC_LOG_FAILURE(opts_, memcache::failure::Category::kInvalidConfig,
                     "Pool {}: pool_locality is not a string", name);
    } else {
      auto str = jlocality->stringPiece();
      if (str == "cluster") {
        if (opts_.cluster_pools_timeout_ms != 0) {
          timeout = std::chrono::milliseconds(opts_.cluster_pools_timeout_ms);
        }
      } else if (str == "region") {
        if (opts_.regional_pools_timeout_ms != 0) {
          timeout = std::chrono::milliseconds(opts_.regional_pools_timeout_ms);
        }
      } else {
        MC_LOG_FAILURE(opts_, memcache::failure::Category::kInvalidConfig,
                       "Pool {}: '{}' pool locality is not supported",
                       name, str);
      }
    }
  }

  // region & cluster
  std::string region, cluster;
  if (auto jregion = json.get_ptr("region")) {
    if (!jregion->isString()) {
      MC_LOG_FAILURE(opts_, memcache::failure::Category::kInvalidConfig,
                     "Pool {}: pool_region is not a string", name);
    } else {
      region = jregion->stringPiece().str();
    }
  }
  if (auto jcluster = json.get_ptr("cluster")) {
    if (!jcluster->isString()) {
      MC_LOG_FAILURE(opts_, memcache::failure::Category::kInvalidConfig,
                     "Pool {}: pool_cluster is not a string", name);
    } else {
      cluster = jcluster->stringPiece().str();
    }
  }

  if (auto jtimeout = json.get_ptr("server_timeout")) {
    if (!jtimeout->isInt()) {
      MC_LOG_FAILURE(opts_, memcache::failure::Category::kInvalidConfig,
                     "Pool {}: server_timeout is not an int", name);
    } else {
      timeout = std::chrono::milliseconds(jtimeout->getInt());
    }
  }

  if (!region.empty() && !cluster.empty()) {
    auto& route = opts_.default_route;
    if (region == route.getRegion() && cluster == route.getCluster()) {
      if (opts_.within_cluster_timeout_ms != 0) {
        timeout = std::chrono::milliseconds(opts_.within_cluster_timeout_ms);
      }
    } else if (region == route.getRegion()) {
      if (opts_.cross_cluster_timeout_ms != 0) {
        timeout = std::chrono::milliseconds(opts_.cross_cluster_timeout_ms);
      }
    } else {
      if (opts_.cross_region_timeout_ms != 0) {
        timeout = std::chrono::milliseconds(opts_.cross_region_timeout_ms);
      }
    }
  }

  auto protocol = parseProtocol(json, mc_ascii_protocol);

  bool keep_routing_prefix = false;
  if (auto jkeep_routing_prefix = json.get_ptr("keep_routing_prefix")) {
    checkLogic(jkeep_routing_prefix->isBool(),
               "Pool {}: keep_routing_prefix is not a bool");
    keep_routing_prefix = jkeep_routing_prefix->getBool();
  }

  uint64_t qosClass = opts_.default_qos_class;
  uint64_t qosPath = opts_.default_qos_path;
  if (auto jqos = json.get_ptr("qos")) {
    parseQos(folly::sformat("Pool {}", name), *jqos, qosClass, qosPath);
  }

  bool useSsl = false;
  if (auto juseSsl = json.get_ptr("use_ssl")) {
    checkLogic(juseSsl->isBool(), "Pool {}: use_ssl is not a bool", name);
    useSsl = juseSsl->getBool();
  }

  // servers
  auto jservers = json.get_ptr("servers");
  checkLogic(jservers, "Pool {}: servers not found", name);
  checkLogic(jservers->isArray(), "Pool {}: servers is not an array", name);
  auto clientPool = std::make_shared<ClientPool>(name);
  for (size_t i = 0; i < jservers->size(); ++i) {
    const auto& server = jservers->at(i);
    std::shared_ptr<AccessPoint> ap;
    bool serverUseSsl = useSsl;
    uint64_t serverQosClass = qosClass;
    uint64_t serverQosPath = qosPath;
    checkLogic(server.isString() || server.isObject(),
               "Pool {}: server #{} is not a string/object", name, i);
    if (server.isString()) {
      // we support both host:port and host:port:protocol
      ap = AccessPoint::create(server.stringPiece(), protocol);
      checkLogic(ap != nullptr,
                 "Pool {}: invalid server {}", name, server.stringPiece());
    } else { // object
      auto jhostname = server.get_ptr("hostname");
      checkLogic(jhostname,
                 "Pool {}: hostname not found for server #{}", name, i);
      checkLogic(jhostname->isString(),
                 "Pool {}: hostname is not a string for server #{}", name, i);

      if (auto jqos = server.get_ptr("qos")) {
        parseQos(folly::sformat("Pool {}, server #{}", name, i),
                 *jqos, qosClass, qosPath);
      }

      if (auto juseSsl = server.get_ptr("use_ssl")) {
        checkLogic(juseSsl->isBool(),
                   "Pool {}: use_ssl is not a bool for server #{}", name, i);
        serverUseSsl = juseSsl->getBool();
      }

      ap = AccessPoint::create(jhostname->stringPiece(),
                               parseProtocol(server, protocol));
      checkLogic(ap != nullptr, "Pool {}: invalid server #{}", name, i);
    }

    auto client = clientPool->emplaceClient(
      timeout,
      std::move(ap),
      keep_routing_prefix,
      serverUseSsl,
      serverQosClass,
      serverQosPath);

    clients_.push_back(std::move(client));
  } // servers

  // weights
  if (auto jweights = json.get_ptr("weights")) {
    clientPool->setWeights(*jweights);
  }

  pools_.emplace(name, clientPool);
  return clientPool;
}