Home | History | Annotate | Download | only in audio
      1 /*
      2  * Copyright (C) 2017 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 #define LOG_TAG "media_omx_hidl_audio_enc_test"
     18 #ifdef __LP64__
     19 #define OMX_ANDROID_COMPILE_AS_32BIT_ON_64BIT_PLATFORMS
     20 #endif
     21 
     22 #include <android-base/logging.h>
     23 
     24 #include <android/hardware/media/omx/1.0/IOmx.h>
     25 #include <android/hardware/media/omx/1.0/IOmxNode.h>
     26 #include <android/hardware/media/omx/1.0/IOmxObserver.h>
     27 #include <android/hardware/media/omx/1.0/types.h>
     28 #include <android/hidl/allocator/1.0/IAllocator.h>
     29 #include <android/hidl/memory/1.0/IMapper.h>
     30 #include <android/hidl/memory/1.0/IMemory.h>
     31 
     32 using ::android::hardware::media::omx::V1_0::IOmx;
     33 using ::android::hardware::media::omx::V1_0::IOmxObserver;
     34 using ::android::hardware::media::omx::V1_0::IOmxNode;
     35 using ::android::hardware::media::omx::V1_0::Message;
     36 using ::android::hardware::media::omx::V1_0::CodecBuffer;
     37 using ::android::hardware::media::omx::V1_0::PortMode;
     38 using ::android::hidl::allocator::V1_0::IAllocator;
     39 using ::android::hidl::memory::V1_0::IMemory;
     40 using ::android::hidl::memory::V1_0::IMapper;
     41 using ::android::hardware::Return;
     42 using ::android::hardware::Void;
     43 using ::android::hardware::hidl_vec;
     44 using ::android::hardware::hidl_string;
     45 using ::android::sp;
     46 
     47 #include <VtsHalHidlTargetTestBase.h>
     48 #include <getopt.h>
     49 #include <media_audio_hidl_test_common.h>
     50 #include <media_hidl_test_common.h>
     51 #include <fstream>
     52 
     53 // A class for test environment setup
     54 class ComponentTestEnvironment : public ::testing::Environment {
     55    public:
     56     virtual void SetUp() {}
     57     virtual void TearDown() {}
     58 
     59     ComponentTestEnvironment() : instance("default"), res("/sdcard/media/") {}
     60 
     61     void setInstance(const char* _instance) { instance = _instance; }
     62 
     63     void setComponent(const char* _component) { component = _component; }
     64 
     65     void setRole(const char* _role) { role = _role; }
     66 
     67     void setRes(const char* _res) { res = _res; }
     68 
     69     const hidl_string getInstance() const { return instance; }
     70 
     71     const hidl_string getComponent() const { return component; }
     72 
     73     const hidl_string getRole() const { return role; }
     74 
     75     const hidl_string getRes() const { return res; }
     76 
     77     int initFromOptions(int argc, char** argv) {
     78         static struct option options[] = {
     79             {"instance", required_argument, 0, 'I'},
     80             {"component", required_argument, 0, 'C'},
     81             {"role", required_argument, 0, 'R'},
     82             {"res", required_argument, 0, 'P'},
     83             {0, 0, 0, 0}};
     84 
     85         while (true) {
     86             int index = 0;
     87             int c = getopt_long(argc, argv, "I:C:R:P:", options, &index);
     88             if (c == -1) {
     89                 break;
     90             }
     91 
     92             switch (c) {
     93                 case 'I':
     94                     setInstance(optarg);
     95                     break;
     96                 case 'C':
     97                     setComponent(optarg);
     98                     break;
     99                 case 'R':
    100                     setRole(optarg);
    101                     break;
    102                 case 'P':
    103                     setRes(optarg);
    104                     break;
    105                 case '?':
    106                     break;
    107             }
    108         }
    109 
    110         if (optind < argc) {
    111             fprintf(stderr,
    112                     "unrecognized option: %s\n\n"
    113                     "usage: %s <gtest options> <test options>\n\n"
    114                     "test options are:\n\n"
    115                     "-I, --instance: HAL instance to test\n"
    116                     "-C, --component: OMX component to test\n"
    117                     "-R, --role: OMX component Role\n"
    118                     "-P, --res: Resource files directory location\n",
    119                     argv[optind ?: 1], argv[0]);
    120             return 2;
    121         }
    122         return 0;
    123     }
    124 
    125    private:
    126     hidl_string instance;
    127     hidl_string component;
    128     hidl_string role;
    129     hidl_string res;
    130 };
    131 
    132 static ComponentTestEnvironment* gEnv = nullptr;
    133 
    134 // audio encoder test fixture class
    135 class AudioEncHidlTest : public ::testing::VtsHalHidlTargetTestBase {
    136    private:
    137     typedef ::testing::VtsHalHidlTargetTestBase Super;
    138    public:
    139     ::std::string getTestCaseInfo() const override {
    140         return ::std::string() +
    141                 "Component: " + gEnv->getComponent().c_str() + " | " +
    142                 "Role: " + gEnv->getRole().c_str() + " | " +
    143                 "Instance: " + gEnv->getInstance().c_str() + " | " +
    144                 "Res: " + gEnv->getRes().c_str();
    145     }
    146 
    147     virtual void SetUp() override {
    148         Super::SetUp();
    149         disableTest = false;
    150         android::hardware::media::omx::V1_0::Status status;
    151         omx = Super::getService<IOmx>(gEnv->getInstance());
    152         ASSERT_NE(omx, nullptr);
    153         observer =
    154             new CodecObserver([this](Message msg, const BufferInfo* buffer) {
    155                 handleMessage(msg, buffer);
    156             });
    157         ASSERT_NE(observer, nullptr);
    158         if (strncmp(gEnv->getComponent().c_str(), "OMX.", 4) != 0)
    159             disableTest = true;
    160         EXPECT_TRUE(omx->allocateNode(
    161                            gEnv->getComponent(), observer,
    162                            [&](android::hardware::media::omx::V1_0::Status _s,
    163                                sp<IOmxNode> const& _nl) {
    164                                status = _s;
    165                                this->omxNode = _nl;
    166                            })
    167                         .isOk());
    168         ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
    169         ASSERT_NE(omxNode, nullptr);
    170         ASSERT_NE(gEnv->getRole().empty(), true) << "Invalid Component Role";
    171         struct StringToName {
    172             const char* Name;
    173             standardComp CompName;
    174         };
    175         const StringToName kStringToName[] = {
    176             {"amrnb", amrnb}, {"amrwb", amrwb}, {"aac", aac}, {"flac", flac},
    177         };
    178         const size_t kNumStringToName =
    179             sizeof(kStringToName) / sizeof(kStringToName[0]);
    180         const char* pch;
    181         char substring[OMX_MAX_STRINGNAME_SIZE];
    182         strcpy(substring, gEnv->getRole().c_str());
    183         pch = strchr(substring, '.');
    184         ASSERT_NE(pch, nullptr);
    185         compName = unknown_comp;
    186         for (size_t i = 0; i < kNumStringToName; ++i) {
    187             if (!strcasecmp(pch + 1, kStringToName[i].Name)) {
    188                 compName = kStringToName[i].CompName;
    189                 break;
    190             }
    191         }
    192         if (compName == unknown_comp) disableTest = true;
    193         struct CompToCoding {
    194             standardComp CompName;
    195             OMX_AUDIO_CODINGTYPE eEncoding;
    196         };
    197         static const CompToCoding kCompToCoding[] = {
    198             {amrnb, OMX_AUDIO_CodingAMR},
    199             {amrwb, OMX_AUDIO_CodingAMR},
    200             {aac, OMX_AUDIO_CodingAAC},
    201             {flac, OMX_AUDIO_CodingFLAC},
    202         };
    203         static const size_t kNumCompToCoding =
    204             sizeof(kCompToCoding) / sizeof(kCompToCoding[0]);
    205         size_t i;
    206         for (i = 0; i < kNumCompToCoding; ++i) {
    207             if (kCompToCoding[i].CompName == compName) {
    208                 eEncoding = kCompToCoding[i].eEncoding;
    209                 break;
    210             }
    211         }
    212         if (i == kNumCompToCoding) disableTest = true;
    213         eosFlag = false;
    214         if (disableTest) std::cout << "[   WARN   ] Test Disabled \n";
    215     }
    216 
    217     virtual void TearDown() override {
    218         if (omxNode != nullptr) {
    219             // If you have encountered a fatal failure, it is possible that
    220             // freeNode() will not go through. Instead of hanging the app.
    221             // let it pass through and report errors
    222             if (::testing::Test::HasFatalFailure()) return;
    223             EXPECT_TRUE((omxNode->freeNode()).isOk());
    224             omxNode = nullptr;
    225         }
    226         Super::TearDown();
    227     }
    228 
    229     // callback function to process messages received by onMessages() from IL
    230     // client.
    231     void handleMessage(Message msg, const BufferInfo* buffer) {
    232         (void)buffer;
    233 
    234         if (msg.type == Message::Type::FILL_BUFFER_DONE) {
    235             if (msg.data.extendedBufferData.flags & OMX_BUFFERFLAG_EOS) {
    236                 eosFlag = true;
    237             }
    238             if (msg.data.extendedBufferData.rangeLength != 0) {
    239 #define WRITE_OUTPUT 0
    240 #if WRITE_OUTPUT
    241                 static int count = 0;
    242                 FILE* ofp = nullptr;
    243                 if (count)
    244                     ofp = fopen("out.bin", "ab");
    245                 else
    246                     ofp = fopen("out.bin", "wb");
    247                 if (ofp != nullptr) {
    248                     fwrite(static_cast<void*>(buffer->mMemory->getPointer()),
    249                            sizeof(char),
    250                            msg.data.extendedBufferData.rangeLength, ofp);
    251                     fclose(ofp);
    252                     count++;
    253                 }
    254 #endif
    255             }
    256         }
    257     }
    258 
    259     enum standardComp {
    260         amrnb,
    261         amrwb,
    262         aac,
    263         flac,
    264         unknown_comp,
    265     };
    266 
    267     sp<IOmx> omx;
    268     sp<CodecObserver> observer;
    269     sp<IOmxNode> omxNode;
    270     standardComp compName;
    271     OMX_AUDIO_CODINGTYPE eEncoding;
    272     bool disableTest;
    273     bool eosFlag;
    274 
    275    protected:
    276     static void description(const std::string& description) {
    277         RecordProperty("description", description);
    278     }
    279 };
    280 
    281 // Set Default port param.
    282 void setDefaultPortParam(sp<IOmxNode> omxNode, OMX_U32 portIndex,
    283                          OMX_AUDIO_CODINGTYPE eEncoding,
    284                          AudioEncHidlTest::standardComp comp, int32_t nChannels,
    285                          int32_t nSampleRate, int32_t nBitRate) {
    286     android::hardware::media::omx::V1_0::Status status;
    287 
    288     OMX_PARAM_PORTDEFINITIONTYPE portDef;
    289     status = getPortParam(omxNode, OMX_IndexParamPortDefinition, portIndex,
    290                           &portDef);
    291     EXPECT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
    292 
    293     portDef.format.audio.bFlagErrorConcealment = OMX_TRUE;
    294     portDef.format.audio.eEncoding = eEncoding;
    295     status = setPortParam(omxNode, OMX_IndexParamPortDefinition, portIndex,
    296                           &portDef);
    297     EXPECT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
    298 
    299     std::vector<int32_t> arrProfile;
    300     int32_t profile;
    301     if ((int)eEncoding == OMX_AUDIO_CodingAAC) {
    302         enumerateProfile(omxNode, portIndex, &arrProfile);
    303         if (arrProfile.empty() == true) ASSERT_TRUE(false);
    304         profile = arrProfile[0];
    305     }
    306 
    307     switch ((int)eEncoding) {
    308         case OMX_AUDIO_CodingFLAC:
    309             setupFLACPort(omxNode, portIndex, nChannels, nSampleRate,
    310                           5 /* nCompressionLevel */);
    311             break;
    312         case OMX_AUDIO_CodingAMR:
    313             setupAMRPort(omxNode, portIndex, nBitRate,
    314                          (comp == AudioEncHidlTest::standardComp::amrwb));
    315             break;
    316         case OMX_AUDIO_CodingAAC:
    317             setupAACPort(omxNode, portIndex,
    318                          static_cast<OMX_AUDIO_AACPROFILETYPE>(profile),
    319                          OMX_AUDIO_AACStreamFormatMP4FF, nChannels, nBitRate,
    320                          nSampleRate);
    321             break;
    322         default:
    323             break;
    324     }
    325 }
    326 
    327 // LookUpTable of clips and metadata for component testing
    328 void GetURLForComponent(AudioEncHidlTest::standardComp comp, char* mURL) {
    329     struct CompToURL {
    330         AudioEncHidlTest::standardComp comp;
    331         const char* mURL;
    332     };
    333     static const CompToURL kCompToURL[] = {
    334         {AudioEncHidlTest::standardComp::aac, "bbb_raw_2ch_48khz_s16le.raw"},
    335         {AudioEncHidlTest::standardComp::amrnb, "bbb_raw_1ch_8khz_s16le.raw"},
    336         {AudioEncHidlTest::standardComp::amrwb, "bbb_raw_1ch_16khz_s16le.raw"},
    337         {AudioEncHidlTest::standardComp::flac, "bbb_raw_2ch_48khz_s16le.raw"},
    338     };
    339 
    340     for (size_t i = 0; i < sizeof(kCompToURL) / sizeof(kCompToURL[0]); ++i) {
    341         if (kCompToURL[i].comp == comp) {
    342             strcat(mURL, kCompToURL[i].mURL);
    343             return;
    344         }
    345     }
    346 }
    347 
    348 // blocking call to ensures application to Wait till all the inputs are consumed
    349 void waitOnInputConsumption(sp<IOmxNode> omxNode, sp<CodecObserver> observer,
    350                             android::Vector<BufferInfo>* iBuffer,
    351                             android::Vector<BufferInfo>* oBuffer) {
    352     android::hardware::media::omx::V1_0::Status status;
    353     Message msg;
    354     int timeOut = TIMEOUT_COUNTER_Q;
    355 
    356     while (timeOut--) {
    357         size_t i = 0;
    358         status =
    359             observer->dequeueMessage(&msg, DEFAULT_TIMEOUT_Q, iBuffer, oBuffer);
    360         ASSERT_EQ(status,
    361                   android::hardware::media::omx::V1_0::Status::TIMED_OUT);
    362         // status == TIMED_OUT, it could be due to process time being large
    363         // than DEFAULT_TIMEOUT or component needs output buffers to start
    364         // processing.
    365         for (; i < iBuffer->size(); i++) {
    366             if ((*iBuffer)[i].owner != client) break;
    367         }
    368         if (i == iBuffer->size()) break;
    369 
    370         // Dispatch an output buffer assuming outQueue.empty() is true
    371         size_t index;
    372         if ((index = getEmptyBufferID(oBuffer)) < oBuffer->size()) {
    373             ASSERT_NO_FATAL_FAILURE(
    374                 dispatchOutputBuffer(omxNode, oBuffer, index));
    375             timeOut = TIMEOUT_COUNTER_Q;
    376         }
    377     }
    378 }
    379 
    380 // Encode N Frames
    381 void encodeNFrames(sp<IOmxNode> omxNode, sp<CodecObserver> observer,
    382                    android::Vector<BufferInfo>* iBuffer,
    383                    android::Vector<BufferInfo>* oBuffer, uint32_t nFrames,
    384                    int32_t samplesPerFrame, int32_t nChannels,
    385                    int32_t nSampleRate, std::ifstream& eleStream,
    386                    bool signalEOS = true) {
    387     android::hardware::media::omx::V1_0::Status status;
    388     Message msg;
    389     size_t index;
    390     int bytesCount = samplesPerFrame * nChannels * 2;
    391     int32_t timestampIncr =
    392         (int)(((float)samplesPerFrame / nSampleRate) * 1000000);
    393     uint64_t timestamp = 0;
    394     uint32_t flags = 0;
    395     int timeOut = TIMEOUT_COUNTER_Q;
    396     bool iQueued, oQueued;
    397 
    398     while (1) {
    399         iQueued = oQueued = false;
    400         status =
    401             observer->dequeueMessage(&msg, DEFAULT_TIMEOUT_Q, iBuffer, oBuffer);
    402         if (status == android::hardware::media::omx::V1_0::Status::OK)
    403             ASSERT_TRUE(false);
    404 
    405         if (nFrames == 0) break;
    406 
    407         // Dispatch input buffer
    408         if ((index = getEmptyBufferID(iBuffer)) < iBuffer->size()) {
    409             char* ipBuffer = static_cast<char*>(
    410                 static_cast<void*>((*iBuffer)[index].mMemory->getPointer()));
    411             ASSERT_LE(bytesCount,
    412                       static_cast<int>((*iBuffer)[index].mMemory->getSize()));
    413             eleStream.read(ipBuffer, bytesCount);
    414             if (eleStream.gcount() != bytesCount) break;
    415             flags = OMX_BUFFERFLAG_ENDOFFRAME;
    416             if (signalEOS && (nFrames == 1)) flags |= OMX_BUFFERFLAG_EOS;
    417             ASSERT_NO_FATAL_FAILURE(dispatchInputBuffer(
    418                 omxNode, iBuffer, index, bytesCount, flags, timestamp));
    419             timestamp += timestampIncr;
    420             nFrames--;
    421             iQueued = true;
    422         }
    423         // Dispatch output buffer
    424         if ((index = getEmptyBufferID(oBuffer)) < oBuffer->size()) {
    425             ASSERT_NO_FATAL_FAILURE(
    426                 dispatchOutputBuffer(omxNode, oBuffer, index));
    427             oQueued = true;
    428         }
    429         // Reset Counters when either input or output buffer is dispatched
    430         if (iQueued || oQueued)
    431             timeOut = TIMEOUT_COUNTER_Q;
    432         else
    433             timeOut--;
    434         if (timeOut == 0) {
    435             ASSERT_TRUE(false) << "Wait on Input/Output is found indefinite";
    436         }
    437     }
    438 }
    439 
    440 // set component role
    441 TEST_F(AudioEncHidlTest, SetRole) {
    442     description("Test Set Component Role");
    443     if (disableTest) return;
    444     android::hardware::media::omx::V1_0::Status status;
    445     status = setRole(omxNode, gEnv->getRole().c_str());
    446     ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
    447 }
    448 
    449 // port format enumeration
    450 TEST_F(AudioEncHidlTest, EnumeratePortFormat) {
    451     description("Test Component on Mandatory Port Parameters (Port Format)");
    452     if (disableTest) return;
    453     android::hardware::media::omx::V1_0::Status status;
    454     uint32_t kPortIndexInput = 0, kPortIndexOutput = 1;
    455     status = setRole(omxNode, gEnv->getRole().c_str());
    456     ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
    457     OMX_PORT_PARAM_TYPE params;
    458     status = getParam(omxNode, OMX_IndexParamAudioInit, &params);
    459     if (status == ::android::hardware::media::omx::V1_0::Status::OK) {
    460         ASSERT_EQ(params.nPorts, 2U);
    461         kPortIndexInput = params.nStartPortNumber;
    462         kPortIndexOutput = kPortIndexInput + 1;
    463     }
    464     status = setAudioPortFormat(omxNode, kPortIndexInput, OMX_AUDIO_CodingPCM);
    465     EXPECT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
    466     status = setAudioPortFormat(omxNode, kPortIndexOutput, eEncoding);
    467     EXPECT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
    468 }
    469 
    470 // test raw stream encode
    471 TEST_F(AudioEncHidlTest, SimpleEncodeTest) {
    472     description("Tests Basic encoding and EOS");
    473     if (disableTest) return;
    474     android::hardware::media::omx::V1_0::Status status;
    475     uint32_t kPortIndexInput = 0, kPortIndexOutput = 1;
    476     status = setRole(omxNode, gEnv->getRole().c_str());
    477     ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
    478     OMX_PORT_PARAM_TYPE params;
    479     status = getParam(omxNode, OMX_IndexParamAudioInit, &params);
    480     if (status == ::android::hardware::media::omx::V1_0::Status::OK) {
    481         ASSERT_EQ(params.nPorts, 2U);
    482         kPortIndexInput = params.nStartPortNumber;
    483         kPortIndexOutput = kPortIndexInput + 1;
    484     }
    485     char mURL[512];
    486     strcpy(mURL, gEnv->getRes().c_str());
    487     GetURLForComponent(compName, mURL);
    488 
    489     std::ifstream eleStream;
    490 
    491     // Configure input port
    492     int32_t nChannels = 2;
    493     int32_t nSampleRate = 44100;
    494     int32_t samplesPerFrame = 1024;
    495     int32_t nBitRate = 128000;
    496     switch (compName) {
    497         case amrnb:
    498             nChannels = 1;
    499             nSampleRate = 8000;
    500             samplesPerFrame = 160;
    501             nBitRate = 7400;
    502             break;
    503         case amrwb:
    504             nChannels = 1;
    505             nSampleRate = 16000;
    506             samplesPerFrame = 160;
    507             nBitRate = 15850;
    508             break;
    509         case aac:
    510             nChannels = 2;
    511             nSampleRate = 48000;
    512             samplesPerFrame = 1024;
    513             nBitRate = 128000;
    514             break;
    515         case flac:
    516             nChannels = 2;
    517             nSampleRate = 48000;
    518             samplesPerFrame = 1152;
    519             nBitRate = 128000;
    520             break;
    521         default:
    522             ASSERT_TRUE(false);
    523     }
    524     setupPCMPort(omxNode, kPortIndexInput, nChannels, OMX_NumericalDataSigned,
    525                  16, nSampleRate, OMX_AUDIO_PCMModeLinear);
    526 
    527     // Configure output port
    528     ASSERT_NO_FATAL_FAILURE(setDefaultPortParam(omxNode, kPortIndexOutput,
    529                                                 eEncoding, compName, nChannels,
    530                                                 nSampleRate, nBitRate));
    531 
    532     android::Vector<BufferInfo> iBuffer, oBuffer;
    533 
    534     // set state to idle
    535     ASSERT_NO_FATAL_FAILURE(changeStateLoadedtoIdle(omxNode, observer, &iBuffer,
    536                                                     &oBuffer, kPortIndexInput,
    537                                                     kPortIndexOutput));
    538     // set state to executing
    539     ASSERT_NO_FATAL_FAILURE(changeStateIdletoExecute(omxNode, observer));
    540 
    541     eleStream.open(mURL, std::ifstream::binary);
    542     ASSERT_EQ(eleStream.is_open(), true);
    543     ASSERT_NO_FATAL_FAILURE(encodeNFrames(omxNode, observer, &iBuffer, &oBuffer,
    544                                           128, samplesPerFrame, nChannels,
    545                                           nSampleRate, eleStream));
    546     eleStream.close();
    547 
    548     ASSERT_NO_FATAL_FAILURE(
    549         waitOnInputConsumption(omxNode, observer, &iBuffer, &oBuffer));
    550     ASSERT_NO_FATAL_FAILURE(
    551         testEOS(omxNode, observer, &iBuffer, &oBuffer, false, eosFlag));
    552     // set state to idle
    553     ASSERT_NO_FATAL_FAILURE(
    554         changeStateExecutetoIdle(omxNode, observer, &iBuffer, &oBuffer));
    555     // set state to executing
    556     ASSERT_NO_FATAL_FAILURE(changeStateIdletoLoaded(omxNode, observer, &iBuffer,
    557                                                     &oBuffer, kPortIndexInput,
    558                                                     kPortIndexOutput));
    559 }
    560 
    561 int main(int argc, char** argv) {
    562     gEnv = new ComponentTestEnvironment();
    563     ::testing::AddGlobalTestEnvironment(gEnv);
    564     ::testing::InitGoogleTest(&argc, argv);
    565     int status = gEnv->initFromOptions(argc, argv);
    566     if (status == 0) {
    567         status = RUN_ALL_TESTS();
    568         ALOGI("Test result = %d", status);
    569     }
    570     return status;
    571 }
    572