Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit e124e425 authored by Yangster-mac's avatar Yangster-mac
Browse files

Interface of writing key value pair atom to socket and parsing from statsd.

Test: statsd unit test
BUG: b/114231161

Change-Id: I3543900934b5e8e0677bf1e7cc454d61064a2475
parent 4b719a7c
Loading
Loading
Loading
Loading
+65 −0
Original line number Diff line number Diff line
@@ -175,6 +175,56 @@ bool LogEvent::write(float value) {
    return false;
}



bool LogEvent::writeKeyValuePairs(const std::map<int32_t, int64_t>& int_map,
                                  const std::map<int32_t, std::string>& string_map,
                                  const std::map<int32_t, float>& float_map) {
    if (mContext) {
         if (android_log_write_list_begin(mContext) < 0) {
            return false;
         }
         for (const auto& itr : int_map) {
             if (android_log_write_list_begin(mContext) < 0) {
                return false;
             }
             write(itr.first);
             write(itr.second);
             if (android_log_write_list_end(mContext) < 0) {
                return false;
             }
         }

         for (const auto& itr : string_map) {
             if (android_log_write_list_begin(mContext) < 0) {
                return false;
             }
             write(itr.first);
             write(itr.second.c_str());
             if (android_log_write_list_end(mContext) < 0) {
                return false;
             }
         }

         for (const auto& itr : float_map) {
             if (android_log_write_list_begin(mContext) < 0) {
                return false;
             }
             write(itr.first);
             write(itr.second);
             if (android_log_write_list_end(mContext) < 0) {
                return false;
             }
         }

         if (android_log_write_list_end(mContext) < 0) {
            return false;
         }
         return true;
    }
    return false;
}

bool LogEvent::write(const std::vector<AttributionNodeInternal>& nodes) {
    if (mContext) {
         if (android_log_write_list_begin(mContext) < 0) {
@@ -225,6 +275,7 @@ void LogEvent::init(android_log_context context) {
    int i = 0;
    int depth = -1;
    int pos[] = {1, 1, 1};
    bool isKeyValuePairAtom = false;
    do {
        elem = android_log_read_next(context);
        switch ((int)elem.type) {
@@ -232,6 +283,7 @@ void LogEvent::init(android_log_context context) {
                // elem at [0] is EVENT_TYPE_LIST, [1] is the timestamp, [2] is tag id.
                if (i == 2) {
                    mTagId = elem.data.int32;
                    isKeyValuePairAtom = (mTagId == android::util::KEY_VALUE_PAIRS_ATOM);
                } else {
                    if (depth < 0 || depth > 2) {
                        return;
@@ -249,6 +301,11 @@ void LogEvent::init(android_log_context context) {
                    return;
                }

                // Handles the oneof field in KeyValuePair atom.
                if (isKeyValuePairAtom && depth == 2) {
                    pos[depth] = 4;
                }

                mValues.push_back(FieldValue(Field(mTagId, pos, depth), Value(elem.data.float32)));

                pos[depth]++;
@@ -260,6 +317,10 @@ void LogEvent::init(android_log_context context) {
                    return;
                }

                // Handles the oneof field in KeyValuePair atom.
                if (isKeyValuePairAtom && depth == 2) {
                    pos[depth] = 3;
                }
                mValues.push_back(FieldValue(Field(mTagId, pos, depth),
                                             Value(string(elem.data.string, elem.len))));

@@ -274,6 +335,10 @@ void LogEvent::init(android_log_context context) {
                        ALOGE("Depth > 2. Not supported!");
                        return;
                    }
                    // Handles the oneof field in KeyValuePair atom.
                    if (isKeyValuePairAtom && depth == 2) {
                        pos[depth] = 2;
                    }
                    mValues.push_back(
                            FieldValue(Field(mTagId, pos, depth), Value((int64_t)elem.data.int64)));

+3 −0
Original line number Diff line number Diff line
@@ -119,6 +119,9 @@ public:
    bool write(float value);
    bool write(const std::vector<AttributionNodeInternal>& nodes);
    bool write(const AttributionNodeInternal& node);
    bool writeKeyValuePairs(const std::map<int32_t, int64_t>& int_map,
                            const std::map<int32_t, std::string>& string_map,
                            const std::map<int32_t, float>& float_map);

    /**
     * Return a string representation of this event.
+84 −1
Original line number Diff line number Diff line
@@ -89,6 +89,89 @@ TEST(LogEventTest, TestLogParsing) {
    EXPECT_EQ((float)1.1, item7.mValue.float_value);
}

TEST(LogEventTest, TestKeyValuePairsAtomParsing) {
    LogEvent event1(83, 2000);
    std::map<int32_t, int64_t> int_map;
    std::map<int32_t, std::string> string_map;
    std::map<int32_t, float> float_map;

    int_map[11] = 123L;
    int_map[22] = 345L;

    string_map[1] = "test2";
    string_map[2] = "test1";

    float_map[111] = 2.2f;
    float_map[222] = 1.1f;

    EXPECT_TRUE(event1.writeKeyValuePairs(int_map, string_map, float_map));
    event1.init();

    EXPECT_EQ(83, event1.GetTagId());
    const auto& items = event1.getValues();
    EXPECT_EQ((size_t)12, items.size());

    const FieldValue& item0 = event1.getValues()[0];
    EXPECT_EQ(0x2010101, item0.mField.getField());
    EXPECT_EQ(Type::INT, item0.mValue.getType());
    EXPECT_EQ(11, item0.mValue.int_value);

    const FieldValue& item1 = event1.getValues()[1];
    EXPECT_EQ(0x2010182, item1.mField.getField());
    EXPECT_EQ(Type::LONG, item1.mValue.getType());
    EXPECT_EQ(123L, item1.mValue.long_value);

    const FieldValue& item2 = event1.getValues()[2];
    EXPECT_EQ(0x2010201, item2.mField.getField());
    EXPECT_EQ(Type::INT, item2.mValue.getType());
    EXPECT_EQ(22, item2.mValue.int_value);

    const FieldValue& item3 = event1.getValues()[3];
    EXPECT_EQ(0x2010282, item3.mField.getField());
    EXPECT_EQ(Type::LONG, item3.mValue.getType());
    EXPECT_EQ(345L, item3.mValue.long_value);

    const FieldValue& item4 = event1.getValues()[4];
    EXPECT_EQ(0x2010301, item4.mField.getField());
    EXPECT_EQ(Type::INT, item4.mValue.getType());
    EXPECT_EQ(1, item4.mValue.int_value);

    const FieldValue& item5 = event1.getValues()[5];
    EXPECT_EQ(0x2010383, item5.mField.getField());
    EXPECT_EQ(Type::STRING, item5.mValue.getType());
    EXPECT_EQ("test2", item5.mValue.str_value);

    const FieldValue& item6 = event1.getValues()[6];
    EXPECT_EQ(0x2010401, item6.mField.getField());
    EXPECT_EQ(Type::INT, item6.mValue.getType());
    EXPECT_EQ(2, item6.mValue.int_value);

    const FieldValue& item7 = event1.getValues()[7];
    EXPECT_EQ(0x2010483, item7.mField.getField());
    EXPECT_EQ(Type::STRING, item7.mValue.getType());
    EXPECT_EQ("test1", item7.mValue.str_value);

    const FieldValue& item8 = event1.getValues()[8];
    EXPECT_EQ(0x2010501, item8.mField.getField());
    EXPECT_EQ(Type::INT, item8.mValue.getType());
    EXPECT_EQ(111, item8.mValue.int_value);

    const FieldValue& item9 = event1.getValues()[9];
    EXPECT_EQ(0x2010584, item9.mField.getField());
    EXPECT_EQ(Type::FLOAT, item9.mValue.getType());
    EXPECT_EQ(2.2f, item9.mValue.float_value);

    const FieldValue& item10 = event1.getValues()[10];
    EXPECT_EQ(0x2018601, item10.mField.getField());
    EXPECT_EQ(Type::INT, item10.mValue.getType());
    EXPECT_EQ(222, item10.mValue.int_value);

    const FieldValue& item11 = event1.getValues()[11];
    EXPECT_EQ(0x2018684, item11.mField.getField());
    EXPECT_EQ(Type::FLOAT, item11.mValue.getType());
    EXPECT_EQ(1.1f, item11.mValue.float_value);
}

TEST(LogEventTest, TestLogParsing2) {
    LogEvent event1(1, 2000);

@@ -158,7 +241,7 @@ TEST(LogEventTest, TestLogParsing2) {
    EXPECT_EQ((float)1.1, item7.mValue.float_value);
}

TEST(LogEventTest, TestKeyValuePairsAtomParsing) {
TEST(LogEventTest, TestKeyValuePairsEvent) {
    std::map<int32_t, int64_t> int_map;
    std::map<int32_t, std::string> string_map;
    std::map<int32_t, float> float_map;
+0 −10
Original line number Diff line number Diff line
@@ -184,16 +184,6 @@ int collate_atom(const Descriptor *atom, AtomDecl *atomDecl,
    expectedNumber++;
  }

  // Skips the key value pair atom.
  for (map<int, const FieldDescriptor *>::const_iterator it = fields.begin();
       it != fields.end(); it++) {
    const FieldDescriptor *field = it->second;
    java_type_t javaType = java_type(field);
    if (javaType == JAVA_TYPE_KEY_VALUE_PAIR) {
      return 0;
    }
  }

  // Check that only allowed types are present. Remove any invalid ones.
  for (map<int, const FieldDescriptor *>::const_iterator it = fields.begin();
       it != fields.end(); it++) {
+107 −4
Original line number Diff line number Diff line
@@ -235,6 +235,10 @@ static int write_stats_log_cpp(FILE *out, const Atoms &atoms,
                                 chainField.name.c_str(), chainField.name.c_str());
                    }
                }
            } else if (*arg == JAVA_TYPE_KEY_VALUE_PAIR) {
                fprintf(out, ", const std::map<int, int64_t>& arg%d_1, "
                             "const std::map<int, char const*>& arg%d_2, "
                             "const std::map<int, float>& arg%d_3", argIndex, argIndex, argIndex);
            } else {
                fprintf(out, ", %s arg%d", cpp_type_name(*arg), argIndex);
            }
@@ -276,6 +280,30 @@ static int write_stats_log_cpp(FILE *out, const Atoms &atoms,
                }
                fprintf(out, "        event.end();\n");
                fprintf(out, "    }\n");
                fprintf(out, "    event.end();\n\n");
            } else if (*arg == JAVA_TYPE_KEY_VALUE_PAIR) {
                    fprintf(out, "    event.begin();\n\n");
                    fprintf(out, "    for (const auto& it : arg%d_1) {\n", argIndex);
                    fprintf(out, "         event.begin();\n");
                    fprintf(out, "         event << it.first;\n");
                    fprintf(out, "         event << it.second;\n");
                    fprintf(out, "         event.end();\n");
                    fprintf(out, "    }\n");

                    fprintf(out, "    for (const auto& it : arg%d_2) {\n", argIndex);
                    fprintf(out, "         event.begin();\n");
                    fprintf(out, "         event << it.first;\n");
                    fprintf(out, "         event << it.second;\n");
                    fprintf(out, "         event.end();\n");
                    fprintf(out, "    }\n");

                    fprintf(out, "    for (const auto& it : arg%d_3) {\n", argIndex);
                    fprintf(out, "         event.begin();\n");
                    fprintf(out, "         event << it.first;\n");
                    fprintf(out, "         event << it.second;\n");
                    fprintf(out, "         event.end();\n");
                    fprintf(out, "    }\n");

                    fprintf(out, "    event.end();\n\n");
            } else {
                if (*arg == JAVA_TYPE_STRING) {
@@ -317,6 +345,10 @@ static int write_stats_log_cpp(FILE *out, const Atoms &atoms,
                                chainField.name.c_str(), chainField.name.c_str());
                   }
               }
           } else if (*arg == JAVA_TYPE_KEY_VALUE_PAIR) {
                fprintf(out, ", const std::map<int, int64_t>& arg%d_1, "
                             "const std::map<int, char const*>& arg%d_2, "
                             "const std::map<int, float>& arg%d_3", argIndex, argIndex, argIndex);
           } else {
               fprintf(out, ", %s arg%d", cpp_type_name(*arg), argIndex);
           }
@@ -343,6 +375,8 @@ static int write_stats_log_cpp(FILE *out, const Atoms &atoms,
                                chainField.name.c_str(), chainField.name.c_str());
                   }
               }
           } else  if (*arg == JAVA_TYPE_KEY_VALUE_PAIR) {
                fprintf(out, ", arg%d_1, arg%d_2, arg%d_3", argIndex, argIndex, argIndex);
           } else {
               fprintf(out, ", arg%d", argIndex);
           }
@@ -496,6 +530,11 @@ static void write_cpp_usage(
                         chainField.name.c_str(), chainField.name.c_str());
                }
            }
        } else if (field->javaType == JAVA_TYPE_KEY_VALUE_PAIR) {
            fprintf(out, ", const std::map<int, int64_t>& %s_int"
                         ", const std::map<int, char const*>& %s_str"
                         ", const std::map<int, float>& %s_float",
                         field->name.c_str(), field->name.c_str(), field->name.c_str());
        } else {
            fprintf(out, ", %s %s", cpp_type_name(field->javaType), field->name.c_str());
        }
@@ -523,6 +562,10 @@ static void write_cpp_method_header(
                            chainField.name.c_str(), chainField.name.c_str());
                    }
                }
            } else if (*arg == JAVA_TYPE_KEY_VALUE_PAIR) {
                fprintf(out, ", const std::map<int, int64_t>& arg%d_1, "
                             "const std::map<int, char const*>& arg%d_2, "
                             "const std::map<int, float>& arg%d_3", argIndex, argIndex, argIndex);
            } else {
                fprintf(out, ", %s arg%d", cpp_type_name(*arg), argIndex);
            }
@@ -637,6 +680,8 @@ static void write_java_usage(FILE* out, const string& method_name, const string&
        field != atom.fields.end(); field++) {
        if (field->javaType == JAVA_TYPE_ATTRIBUTION_CHAIN) {
            fprintf(out, ", android.os.WorkSource workSource");
        } else if (field->javaType == JAVA_TYPE_KEY_VALUE_PAIR) {
            fprintf(out, ", SparseArray<Object> value_map");
        } else {
            fprintf(out, ", %s %s", java_type_name(field->javaType), field->name.c_str());
        }
@@ -658,6 +703,8 @@ static void write_java_method(
                    fprintf(out, ", %s[] %s",
                        java_type_name(chainField.javaType), chainField.name.c_str());
                }
            } else if (*arg == JAVA_TYPE_KEY_VALUE_PAIR) {
                fprintf(out, ", SparseArray<Object> value_map");
            } else {
                fprintf(out, ", %s arg%d", java_type_name(*arg), argIndex);
            }
@@ -746,6 +793,7 @@ write_stats_log_java(FILE* out, const Atoms& atoms, const AtomDecl &attributionD
    fprintf(out, "package android.util;\n");
    fprintf(out, "\n");
    fprintf(out, "import android.os.WorkSource;\n");
    fprintf(out, "import android.util.SparseArray;\n");
    fprintf(out, "import java.util.ArrayList;\n");
    fprintf(out, "\n");
    fprintf(out, "\n");
@@ -837,6 +885,8 @@ jni_array_type_name(java_type_t type)
    switch (type) {
        case JAVA_TYPE_INT:
            return "jintArray";
        case JAVA_TYPE_FLOAT:
            return "jfloatArray";
        case JAVA_TYPE_STRING:
            return "jobjectArray";
        default:
@@ -873,6 +923,9 @@ jni_function_name(const string& method_name, const vector<java_type_t>& signatur
            case JAVA_TYPE_ATTRIBUTION_CHAIN:
              result += "_AttributionChain";
              break;
            case JAVA_TYPE_KEY_VALUE_PAIR:
              result += "_KeyValuePairs";
              break;
            default:
                result += "_UNKNOWN";
                break;
@@ -914,6 +967,8 @@ jni_function_signature(const vector<java_type_t>& signature, const AtomDecl &att
                result += "[";
                result += java_type_signature(chainField.javaType);
            }
        } else if (*arg == JAVA_TYPE_KEY_VALUE_PAIR) {
            result += "Landroid/util/SparseArray;";
        } else {
            result += java_type_signature(*arg);
        }
@@ -922,6 +977,43 @@ jni_function_signature(const vector<java_type_t>& signature, const AtomDecl &att
    return result;
}

static void write_key_value_map_jni(FILE* out) {
   fprintf(out, "    std::map<int, int64_t> int64_t_map;\n");
   fprintf(out, "    std::map<int, float> float_map;\n");
   fprintf(out, "    std::map<int, char const*> string_map;\n\n");

   fprintf(out, "    jclass jmap_class = env->FindClass(\"android/util/SparseArray\");\n");

   fprintf(out, "    jmethodID jget_size_method = env->GetMethodID(jmap_class, \"size\", \"()I\");\n");
   fprintf(out, "    jmethodID jget_key_method = env->GetMethodID(jmap_class, \"keyAt\", \"(I)I\");\n");
   fprintf(out, "    jmethodID jget_value_method = env->GetMethodID(jmap_class, \"valueAt\", \"(I)Ljava/lang/Object;\");\n\n");


   fprintf(out, "    std::vector<std::unique_ptr<ScopedUtfChars>> scoped_ufs;\n\n");

   fprintf(out, "    jclass jlong_class = env->FindClass(\"java/lang/Long\");\n");
   fprintf(out, "    jclass jfloat_class = env->FindClass(\"java/lang/Float\");\n");
   fprintf(out, "    jclass jstring_class = env->FindClass(\"java/lang/String\");\n");
   fprintf(out, "    jmethodID jget_long_method = env->GetMethodID(jlong_class, \"longValue\", \"()J\");\n");
   fprintf(out, "    jmethodID jget_float_method = env->GetMethodID(jfloat_class, \"floatValue\", \"()F\");\n\n");

   fprintf(out, "    jint jsize = env->CallIntMethod(value_map, jget_size_method);\n");
   fprintf(out, "    for(int i = 0; i < jsize; i++) {\n");
   fprintf(out, "        jint key = env->CallIntMethod(value_map, jget_key_method, i);\n");
   fprintf(out, "        jobject jvalue_obj = env->CallObjectMethod(value_map, jget_value_method, i);\n");
   fprintf(out, "        if (jvalue_obj == NULL) { continue; }\n");
   fprintf(out, "        if (env->IsInstanceOf(jvalue_obj, jlong_class)) {\n");
   fprintf(out, "            int64_t_map[key] = env->CallLongMethod(jvalue_obj, jget_long_method);\n");
   fprintf(out, "        } else if (env->IsInstanceOf(jvalue_obj, jfloat_class)) {\n");
   fprintf(out, "            float_map[key] = env->CallFloatMethod(jvalue_obj, jget_float_method);\n");
   fprintf(out, "        } else if (env->IsInstanceOf(jvalue_obj, jstring_class)) {\n");
   fprintf(out, "            std::unique_ptr<ScopedUtfChars> utf(new ScopedUtfChars(env, (jstring)jvalue_obj));\n");
   fprintf(out, "            if (utf->c_str() != NULL) { string_map[key] = utf->c_str(); }\n");
   fprintf(out, "            scoped_ufs.push_back(std::move(utf));\n");
   fprintf(out, "        }\n");
   fprintf(out, "    }\n");
}

static int
write_stats_log_jni(FILE* out, const string& java_method_name, const string& cpp_method_name,
    const set<vector<java_type_t>>& signatures, const AtomDecl &attributionDecl)
@@ -942,6 +1034,8 @@ write_stats_log_jni(FILE* out, const string& java_method_name, const string& cpp
                    fprintf(out, ", %s %s", jni_array_type_name(chainField.javaType),
                        chainField.name.c_str());
                }
            } else if (*arg == JAVA_TYPE_KEY_VALUE_PAIR) {
                fprintf(out, ", jobject value_map");
            } else {
                fprintf(out, ", %s arg%d", jni_type_name(*arg), argIndex);
            }
@@ -954,6 +1048,7 @@ write_stats_log_jni(FILE* out, const string& java_method_name, const string& cpp
        // Prepare strings
        argIndex = 1;
        bool hadStringOrChain = false;
        bool isKeyValuePairAtom = false;
        for (vector<java_type_t>::const_iterator arg = signature->begin();
                arg != signature->end(); arg++) {
            if (*arg == JAVA_TYPE_STRING) {
@@ -1006,18 +1101,23 @@ write_stats_log_jni(FILE* out, const string& java_method_name, const string& cpp
                    }
                    fprintf(out, "\n");
                }
            } else if (*arg == JAVA_TYPE_KEY_VALUE_PAIR) {
                isKeyValuePairAtom = true;
            }
            argIndex++;
        }
        // Emit this to quiet the unused parameter warning if there were no strings or attribution
        // chains.
        if (!hadStringOrChain) {
        if (!hadStringOrChain && !isKeyValuePairAtom) {
            fprintf(out, "    (void)env;\n");
        }
        if (isKeyValuePairAtom) {
            write_key_value_map_jni(out);
        }

        // stats_write call
        argIndex = 1;
        fprintf(out, "   int ret =  android::util::%s(code", cpp_method_name.c_str());
        fprintf(out, "\n    int ret =  android::util::%s(code", cpp_method_name.c_str());
        for (vector<java_type_t>::const_iterator arg = signature->begin();
                arg != signature->end(); arg++) {
            if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
@@ -1030,6 +1130,8 @@ write_stats_log_jni(FILE* out, const string& java_method_name, const string& cpp
                        fprintf(out, ", %s_vec", chainField.name.c_str());
                    }
                }
            } else if (*arg == JAVA_TYPE_KEY_VALUE_PAIR) {
                fprintf(out, ", int64_t_map, string_map, float_map");
            } else {
                const char *argName = (*arg == JAVA_TYPE_STRING) ? "str" : "arg";
                fprintf(out, ", (%s)%s%d", cpp_type_name(*arg), argName, argIndex);
@@ -1063,6 +1165,7 @@ write_stats_log_jni(FILE* out, const string& java_method_name, const string& cpp
            }
            argIndex++;
        }

        fprintf(out, "    return ret;\n");

        fprintf(out, "}\n");