Merge "Merge "Update the comments for all CellIdentity*." am: 2610ad0556 am: 4f95fd8532 am: 06b73ece42"
diff --git a/cmds/statsd/src/StatsLogProcessor.cpp b/cmds/statsd/src/StatsLogProcessor.cpp
index b764ce5..abd2a35 100644
--- a/cmds/statsd/src/StatsLogProcessor.cpp
+++ b/cmds/statsd/src/StatsLogProcessor.cpp
@@ -50,8 +50,8 @@
 const int FIELD_ID_NAME = 2;
 
 StatsLogProcessor::StatsLogProcessor(const sp<UidMap>& uidMap,
-                                     const std::function<void(const vector<uint8_t>&)>& pushLog)
-    : mUidMap(uidMap), mPushLog(pushLog) {
+                                     const std::function<void(const ConfigKey&)>& sendBroadcast)
+    : mUidMap(uidMap), mSendBroadcast(sendBroadcast) {
 }
 
 StatsLogProcessor::~StatsLogProcessor() {
@@ -102,12 +102,27 @@
     }
 }
 
-vector<uint8_t> StatsLogProcessor::onDumpReport(const ConfigKey& key) {
+size_t StatsLogProcessor::GetMetricsSize(const ConfigKey& key) {
     auto it = mMetricsManagers.find(key);
     if (it == mMetricsManagers.end()) {
         ALOGW("Config source %s does not exist", key.ToString().c_str());
-        return vector<uint8_t>();
+        return 0;
     }
+    return it->second->byteSize();
+}
+
+void StatsLogProcessor::onDumpReport(const ConfigKey& key, vector<uint8_t>* outData) {
+    auto it = mMetricsManagers.find(key);
+    if (it == mMetricsManagers.end()) {
+        ALOGW("Config source %s does not exist", key.ToString().c_str());
+        return;
+    }
+
+    // This allows another broadcast to be sent within the rate-limit period if we get close to
+    // filling the buffer again soon.
+    mBroadcastTimesMutex.lock();
+    mLastBroadcastTimes.erase(key);
+    mBroadcastTimesMutex.unlock();
 
     ProtoOutputStream proto;
 
@@ -131,17 +146,18 @@
     uidMap.SerializeToArray(&uidMapBuffer[0], uidMapSize);
     proto.write(FIELD_TYPE_MESSAGE | FIELD_ID_UID_MAP, uidMapBuffer, uidMapSize);
 
-    vector<uint8_t> buffer(proto.size());
-    size_t pos = 0;
-    auto iter = proto.data();
-    while (iter.readBuffer() != NULL) {
-        size_t toRead = iter.currentToRead();
-        std::memcpy(&buffer[pos], iter.readBuffer(), toRead);
-        pos += toRead;
-        iter.rp()->move(toRead);
+    if (outData != nullptr) {
+        outData->clear();
+        outData->resize(proto.size());
+        size_t pos = 0;
+        auto iter = proto.data();
+        while (iter.readBuffer() != NULL) {
+            size_t toRead = iter.currentToRead();
+            std::memcpy(&((*outData)[pos]), iter.readBuffer(), toRead);
+            pos += toRead;
+            iter.rp()->move(toRead);
+        }
     }
-
-    return buffer;
 }
 
 void StatsLogProcessor::OnConfigRemoved(const ConfigKey& key) {
@@ -151,42 +167,34 @@
         mMetricsManagers.erase(it);
         mUidMap->OnConfigRemoved(key);
     }
-    auto flushTime = mLastFlushTimes.find(key);
-    if (flushTime != mLastFlushTimes.end()) {
-        mLastFlushTimes.erase(flushTime);
-    }
+
+    std::lock_guard<std::mutex> lock(mBroadcastTimesMutex);
+    mLastBroadcastTimes.erase(key);
 }
 
 void StatsLogProcessor::flushIfNecessary(uint64_t timestampNs,
                                          const ConfigKey& key,
                                          const unique_ptr<MetricsManager>& metricsManager) {
-    auto lastFlushNs = mLastFlushTimes.find(key);
-    if (lastFlushNs != mLastFlushTimes.end()) {
-        if (timestampNs - lastFlushNs->second < kMinFlushPeriod) {
-            return;
-        }
-    }
+    std::lock_guard<std::mutex> lock(mBroadcastTimesMutex);
 
     size_t totalBytes = metricsManager->byteSize();
-    if (totalBytes > kMaxSerializedBytes) {
-        flush();
-        mLastFlushTimes[key] = std::move(timestampNs);
+    if (totalBytes > .9 * kMaxSerializedBytes) { // Send broadcast so that receivers can pull data.
+        auto lastFlushNs = mLastBroadcastTimes.find(key);
+        if (lastFlushNs != mLastBroadcastTimes.end()) {
+            if (timestampNs - lastFlushNs->second < kMinBroadcastPeriod) {
+                return;
+            }
+        }
+        mLastBroadcastTimes[key] = timestampNs;
+        ALOGD("StatsD requesting broadcast for %s", key.ToString().c_str());
+        mSendBroadcast(key);
+    } else if (totalBytes > kMaxSerializedBytes) { // Too late. We need to start clearing data.
+        // We ignore the return value so we force each metric producer to clear its contents.
+        metricsManager->onDumpReport();
+        ALOGD("StatsD had to toss out metrics for %s", key.ToString().c_str());
     }
 }
 
-void StatsLogProcessor::flush() {
-    // TODO: Take ConfigKey as an argument and flush metrics related to the
-    // ConfigKey. Also, create a wrapper that holds a repeated field of
-    // StatsLogReport's.
-    /*
-    StatsLogReport logReport;
-    const int numBytes = logReport.ByteSize();
-    vector<uint8_t> logReportBuffer(numBytes);
-    logReport.SerializeToArray(&logReportBuffer[0], numBytes);
-    mPushLog(logReportBuffer);
-    */
-}
-
 }  // namespace statsd
 }  // namespace os
 }  // namespace android
diff --git a/cmds/statsd/src/StatsLogProcessor.h b/cmds/statsd/src/StatsLogProcessor.h
index f38d715..2091774 100644
--- a/cmds/statsd/src/StatsLogProcessor.h
+++ b/cmds/statsd/src/StatsLogProcessor.h
@@ -33,7 +33,7 @@
 class StatsLogProcessor : public ConfigListener {
 public:
     StatsLogProcessor(const sp<UidMap>& uidMap,
-                      const std::function<void(const vector<uint8_t>&)>& pushLog);
+                      const std::function<void(const ConfigKey&)>& sendBroadcast);
     virtual ~StatsLogProcessor();
 
     virtual void OnLogEvent(const LogEvent& event);
@@ -41,15 +41,16 @@
     void OnConfigUpdated(const ConfigKey& key, const StatsdConfig& config);
     void OnConfigRemoved(const ConfigKey& key);
 
-    vector<uint8_t> onDumpReport(const ConfigKey& key);
+    size_t GetMetricsSize(const ConfigKey& key);
 
-    /* Request a flush through a binder call. */
-    void flush();
+    void onDumpReport(const ConfigKey& key, vector<uint8_t>* outData);
 
 private:
+    mutable mutex mBroadcastTimesMutex;
+
     std::unordered_map<ConfigKey, std::unique_ptr<MetricsManager>> mMetricsManagers;
 
-    std::unordered_map<ConfigKey, long> mLastFlushTimes;
+    std::unordered_map<ConfigKey, long> mLastBroadcastTimes;
 
     sp<UidMap> mUidMap;  // Reference to the UidMap to lookup app name and version for each uid.
 
@@ -60,17 +61,18 @@
      */
     static const size_t kMaxSerializedBytes = 16 * 1024;
 
-    /* Check if the buffer size exceeds the max buffer size when the new entry is added, and flush
-       the logs to callback clients if true. */
+    /* Check if we should send a broadcast if approaching memory limits and if we're over, we
+     * actually delete the data. */
     void flushIfNecessary(uint64_t timestampNs,
                           const ConfigKey& key,
                           const unique_ptr<MetricsManager>& metricsManager);
 
-    std::function<void(const vector<uint8_t>&)> mPushLog;
+    // Function used to send a broadcast so that receiver for the config key can call getData
+    // to retrieve the stored data.
+    std::function<void(const ConfigKey& key)> mSendBroadcast;
 
-    /* Minimum period between two flushes in nanoseconds. Currently set to 10
-     * minutes. */
-    static const unsigned long long kMinFlushPeriod = 600 * NS_PER_SEC;
+    /* Minimum period between two broadcasts in nanoseconds. Currently set to 60 seconds. */
+    static const unsigned long long kMinBroadcastPeriod = 60 * NS_PER_SEC;
 };
 
 }  // namespace statsd
diff --git a/cmds/statsd/src/StatsService.cpp b/cmds/statsd/src/StatsService.cpp
index 8b76cff..10952a9 100644
--- a/cmds/statsd/src/StatsService.cpp
+++ b/cmds/statsd/src/StatsService.cpp
@@ -73,8 +73,18 @@
 {
     mUidMap = new UidMap();
     mConfigManager = new ConfigManager();
-    mProcessor = new StatsLogProcessor(mUidMap, [](const vector<uint8_t>& log) {
-        // TODO: Update how we send data out of StatsD.
+    mProcessor = new StatsLogProcessor(mUidMap, [this](const ConfigKey& key) {
+        auto sc = getStatsCompanionService();
+        auto receiver = mConfigManager->GetConfigReceiver(key);
+        if (sc == nullptr) {
+            ALOGD("Could not find StatsCompanionService");
+        } else if (receiver.first.size() == 0) {
+            ALOGD("Statscompanion could not find a broadcast receiver for %s",
+                  key.ToString().c_str());
+        } else {
+            sc->sendBroadcast(String16(receiver.first.c_str()),
+                              String16(receiver.second.c_str()));
+        }
     });
 
     mConfigManager->AddListener(mProcessor);
@@ -206,7 +216,11 @@
         }
 
         if (!args[0].compare(String8("send-broadcast"))) {
-            return cmd_trigger_broadcast(args);
+            return cmd_trigger_broadcast(out, args);
+        }
+
+        if (!args[0].compare(String8("print-stats"))) {
+            return cmd_print_stats(out);
         }
 
         if (!args[0].compare(String8("clear-config"))) {
@@ -259,16 +273,56 @@
     fprintf(out, "  NAME          The name of the configuration\n");
     fprintf(out, "\n");
     fprintf(out, "\n");
-    fprintf(out, "usage: adb shell cmd stats send-broadcast PACKAGE CLASS\n");
-    fprintf(out, "  Send a broadcast that triggers one subscriber to fetch metrics.\n");
-    fprintf(out, "  PACKAGE        The name of the package to receive the broadcast.\n");
-    fprintf(out, "  CLASS          The name of the class to receive the broadcast.\n");
+    fprintf(out, "usage: adb shell cmd stats send-broadcast [UID] NAME\n");
+    fprintf(out, "  Send a broadcast that triggers the subscriber to fetch metrics.\n");
+    fprintf(out, "  UID           The uid of the configuration. It is only possible to pass\n");
+    fprintf(out, "                the UID parameter on eng builds. If UID is omitted the\n");
+    fprintf(out, "                calling uid is used.\n");
+    fprintf(out, "  NAME          The name of the configuration\n");
+    fprintf(out, "\n");
+    fprintf(out, "\n");
+    fprintf(out, "usage: adb shell cmd stats print-stats\n");
+    fprintf(out, "  Prints some basic stats.\n");
 }
 
-status_t StatsService::cmd_trigger_broadcast(Vector<String8>& args) {
+status_t StatsService::cmd_trigger_broadcast(FILE* out, Vector<String8>& args) {
+    string name;
+    bool good = false;
+    int uid;
+    const int argCount = args.size();
+    if (argCount == 2) {
+        // Automatically pick the UID
+        uid = IPCThreadState::self()->getCallingUid();
+        // TODO: What if this isn't a binder call? Should we fail?
+        name.assign(args[1].c_str(), args[1].size());
+        good = true;
+    } else if (argCount == 3) {
+        // If it's a userdebug or eng build, then the shell user can
+        // impersonate other uids.
+        if (mEngBuild) {
+            const char* s = args[1].c_str();
+            if (*s != '\0') {
+                char* end = NULL;
+                uid = strtol(s, &end, 0);
+                if (*end == '\0') {
+                    name.assign(args[2].c_str(), args[2].size());
+                    good = true;
+                }
+            }
+        } else {
+            fprintf(out,
+                    "The metrics can only be dumped for other UIDs on eng or userdebug "
+                            "builds.\n");
+        }
+    }
+    if (!good) {
+        print_cmd_help(out);
+        return UNKNOWN_ERROR;
+    }
+    auto receiver = mConfigManager->GetConfigReceiver(ConfigKey(uid, name));
     auto sc = getStatsCompanionService();
-    sc->sendBroadcast(String16(args[1]), String16(args[2]));
-    ALOGD("StatsService::trigger broadcast succeeded");
+    sc->sendBroadcast(String16(receiver.first.c_str()), String16(receiver.second.c_str()));
+    ALOGD("StatsService::trigger broadcast succeeded to %s, %s", args[1].c_str(), args[2].c_str());
     return NO_ERROR;
 }
 
@@ -373,7 +427,8 @@
             }
         }
         if (good) {
-            mProcessor->onDumpReport(ConfigKey(uid, name));
+            vector<uint8_t> data;
+            mProcessor->onDumpReport(ConfigKey(uid, name), &data);
             // TODO: print the returned StatsLogReport to file instead of printing to logcat.
             fprintf(out, "Dump report for Config [%d,%s]\n", uid, name.c_str());
             fprintf(out, "See the StatsLogReport in logcat...\n");
@@ -389,6 +444,15 @@
     }
 }
 
+status_t StatsService::cmd_print_stats(FILE* out) {
+    vector<ConfigKey> configs = mConfigManager->GetAllConfigKeys();
+    for (const ConfigKey& key : configs) {
+        fprintf(out, "Config %s uses %zu bytes\n", key.ToString().c_str(),
+                mProcessor->GetMetricsSize(key));
+    }
+    return NO_ERROR;
+}
+
 status_t StatsService::cmd_print_stats_log(FILE* out, const Vector<String8>& args) {
     long msec = 0;
 
@@ -573,10 +637,14 @@
     mProcessor->OnLogEvent(event);
 }
 
-Status StatsService::getData(const String16& key, vector<uint8_t>* output) {
+Status StatsService::getData(const String16& key, vector <uint8_t>* output) {
     IPCThreadState* ipc = IPCThreadState::self();
+    ALOGD("StatsService::getData with Pid %i, Uid %i", ipc->getCallingPid(),
+          ipc->getCallingUid());
     if (checkCallingPermission(String16(kPermissionDump))) {
-        // TODO: Implement this.
+        string keyStr = string(String8(key).string());
+        ConfigKey configKey(ipc->getCallingUid(), keyStr);
+        mProcessor->onDumpReport(configKey, output);
         return Status::ok();
     } else {
         return Status::fromExceptionCode(binder::Status::EX_SECURITY);
@@ -588,10 +656,9 @@
                                       const String16& package, const String16& cls,
                                       bool* success) {
     IPCThreadState* ipc = IPCThreadState::self();
-    int32_t* uid = reinterpret_cast<int32_t*>(ipc->getCallingUid());
     if (checkCallingPermission(String16(kPermissionDump))) {
         string keyString = string(String8(key).string());
-        ConfigKey configKey(*uid, keyString);
+        ConfigKey configKey(ipc->getCallingUid(), keyString);
         StatsdConfig cfg;
         cfg.ParseFromArray(&config[0], config.size());
         mConfigManager->UpdateConfig(configKey, cfg);
@@ -607,7 +674,8 @@
 Status StatsService::removeConfiguration(const String16& key, bool* success) {
     IPCThreadState* ipc = IPCThreadState::self();
     if (checkCallingPermission(String16(kPermissionDump))) {
-        // TODO: Implement this.
+        string keyStr = string(String8(key).string());
+        mConfigManager->RemoveConfig(ConfigKey(ipc->getCallingUid(), keyStr));
         return Status::ok();
     } else {
         *success = false;
@@ -615,7 +683,7 @@
     }
 }
 
-void StatsService::binderDied(const wp<IBinder>& who) {
+void StatsService::binderDied(const wp <IBinder>& who) {
     for (size_t i = 0; i < mCallbacks.size(); i++) {
         if (IInterface::asBinder(mCallbacks[i]) == who) {
             mCallbacks.removeAt(i);
diff --git a/cmds/statsd/src/StatsService.h b/cmds/statsd/src/StatsService.h
index 0163f94..888f97b 100644
--- a/cmds/statsd/src/StatsService.h
+++ b/cmds/statsd/src/StatsService.h
@@ -124,7 +124,7 @@
     /**
      * Trigger a broadcast.
      */
-    status_t cmd_trigger_broadcast(Vector<String8>& args);
+    status_t cmd_trigger_broadcast(FILE* out, Vector<String8>& args);
 
     /**
      * Handle the config sub-command.
@@ -132,6 +132,11 @@
     status_t cmd_config(FILE* in, FILE* out, FILE* err, Vector<String8>& args);
 
     /**
+     * Prints some basic stats to std out.
+     */
+    status_t cmd_print_stats(FILE* out);
+
+    /**
      * Print the event log.
      */
     status_t cmd_print_stats_log(FILE* out, const Vector<String8>& args);
diff --git a/cmds/statsd/src/config/ConfigManager.cpp b/cmds/statsd/src/config/ConfigManager.cpp
index 3319f6d..9680e4a 100644
--- a/cmds/statsd/src/config/ConfigManager.cpp
+++ b/cmds/statsd/src/config/ConfigManager.cpp
@@ -134,12 +134,34 @@
     }
 }
 
+vector<ConfigKey> ConfigManager::GetAllConfigKeys() {
+    vector<ConfigKey> ret;
+    for (auto it = mConfigs.cbegin(); it != mConfigs.cend(); ++it) {
+        ret.push_back(it->first);
+    }
+    return ret;
+}
+
+const pair<string, string> ConfigManager::GetConfigReceiver(const ConfigKey& key) {
+    auto it = mConfigReceivers.find(key);
+    if (it == mConfigReceivers.end()) {
+        return pair<string,string>();
+    } else {
+        return it->second;
+    }
+}
+
 void ConfigManager::Dump(FILE* out) {
     fprintf(out, "CONFIGURATIONS (%d)\n", (int)mConfigs.size());
     fprintf(out, "     uid name\n");
     for (unordered_map<ConfigKey, StatsdConfig>::const_iterator it = mConfigs.begin();
          it != mConfigs.end(); it++) {
         fprintf(out, "  %6d %s\n", it->first.GetUid(), it->first.GetName().c_str());
+        auto receiverIt = mConfigReceivers.find(it->first);
+        if (receiverIt != mConfigReceivers.end()) {
+            fprintf(out, "    -> received by %s, %s\n", receiverIt->second.first.c_str(),
+                    receiverIt->second.second.c_str());
+        }
         // TODO: Print the contents of the config too.
     }
 }
diff --git a/cmds/statsd/src/config/ConfigManager.h b/cmds/statsd/src/config/ConfigManager.h
index 5b612cc..01d7fb9 100644
--- a/cmds/statsd/src/config/ConfigManager.h
+++ b/cmds/statsd/src/config/ConfigManager.h
@@ -68,6 +68,16 @@
     void SetConfigReceiver(const ConfigKey& key, const string& pkg, const string& cls);
 
     /**
+     * Returns the package name and class name representing the broadcast receiver for this config.
+     */
+    const pair<string, string> GetConfigReceiver(const ConfigKey& key);
+
+    /**
+     * Returns all config keys registered.
+     */
+    vector<ConfigKey> GetAllConfigKeys();
+
+    /**
      * Erase any broadcast receiver associated with this config key.
      */
     void RemoveConfigReceiver(const ConfigKey& key);
diff --git a/cmds/statsd/src/metrics/EventMetricProducer.cpp b/cmds/statsd/src/metrics/EventMetricProducer.cpp
index 74ba40b..bd288a1 100644
--- a/cmds/statsd/src/metrics/EventMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/EventMetricProducer.cpp
@@ -121,7 +121,10 @@
     event.ToProto(*mProto);
     mProto->end(eventToken);
     mProto->end(wrapperToken);
-    // TODO: Find a proper way to derive the size of incoming LogEvent.
+
+    // TODO: Increment mByteSize with a real value. Until this feature is working, we assume 50
+    // bytes.
+    mByteSize += 50;
 }
 
 size_t EventMetricProducer::byteSize() {
diff --git a/cmds/statsd/src/metrics/MetricProducer.h b/cmds/statsd/src/metrics/MetricProducer.h
index c0930e3..c7982a8 100644
--- a/cmds/statsd/src/metrics/MetricProducer.h
+++ b/cmds/statsd/src/metrics/MetricProducer.h
@@ -61,12 +61,15 @@
 
     // TODO: Pass a timestamp as a parameter in onDumpReport and update all its
     // implementations.
+    // onDumpReport returns the proto-serialized output and clears the previously stored contents.
     virtual std::unique_ptr<std::vector<uint8_t>> onDumpReport() = 0;
 
     virtual bool isConditionSliced() const {
         return mConditionSliced;
     };
 
+    // Returns the memory in bytes currently used to store this metric's data. Does not change
+    // state.
     virtual size_t byteSize() = 0;
 
 protected:
diff --git a/cmds/statsd/src/metrics/MetricsManager.h b/cmds/statsd/src/metrics/MetricsManager.h
index 39c79f9..fb16779 100644
--- a/cmds/statsd/src/metrics/MetricsManager.h
+++ b/cmds/statsd/src/metrics/MetricsManager.h
@@ -46,6 +46,8 @@
     // Config source owner can call onDumpReport() to get all the metrics collected.
     std::vector<std::unique_ptr<std::vector<uint8_t>>> onDumpReport();
 
+    // Computes the total byte size of all metrics managed by a single config source.
+    // Does not change the state.
     size_t byteSize();
 
 private:
diff --git a/location/Android.mk b/location/Android.mk
index feeb8ce..50509c6 100644
--- a/location/Android.mk
+++ b/location/Android.mk
@@ -14,4 +14,4 @@
 
 LOCAL_PATH := $(call my-dir)
 
-include $(call all-makefiles-under, $(LOCAL_PATH))
+include $(call all-subdir-makefiles, $(LOCAL_PATH))
\ No newline at end of file
diff --git a/location/tests/locationtests/Android.mk b/location/tests/locationtests/Android.mk
index 902cd96..73b2bb5 100644
--- a/location/tests/locationtests/Android.mk
+++ b/location/tests/locationtests/Android.mk
@@ -10,5 +10,13 @@
 LOCAL_JAVA_LIBRARIES := android.test.runner
 LOCAL_PACKAGE_NAME := FrameworksLocationTests
 
-include $(BUILD_PACKAGE)
+LOCAL_STATIC_JAVA_LIBRARIES := \
+    android-support-test \
+    core-test-rules \
+    guava \
+    mockito-target-minus-junit4 \
+    frameworks-base-testutils \
+    truth-prebuilt \
 
+LOCAL_COMPATIBILITY_SUITE := device-tests
+include $(BUILD_PACKAGE)
diff --git a/location/tests/locationtests/AndroidManifest.xml b/location/tests/locationtests/AndroidManifest.xml
index 1d9df0f..ddb8ea6 100644
--- a/location/tests/locationtests/AndroidManifest.xml
+++ b/location/tests/locationtests/AndroidManifest.xml
@@ -4,9 +4,9 @@
      Licensed under the Apache License, Version 2.0 (the "License");
      you may not use this file except in compliance with the License.
      You may obtain a copy of the License at
-  
+
           http://www.apache.org/licenses/LICENSE-2.0
-  
+
      Unless required by applicable law or agreed to in writing, software
      distributed under the License is distributed on an "AS IS" BASIS,
      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -23,13 +23,13 @@
     <uses-permission android:name="android.permission.WRITE_SETTINGS"/>
     <uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS"/>
     <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
-    
+
     <application>
         <uses-library android:name="android.test.runner" />
     </application>
 
     <instrumentation
-    	android:name="android.test.InstrumentationTestRunner"
-    	android:targetPackage="com.android.frameworks.locationtests"
-    	android:label="Frameworks Location Tests" />
+        android:name="android.support.test.runner.AndroidJUnitRunner"
+        android:targetPackage="com.android.frameworks.locationtests"
+        android:label="Frameworks Location Tests" />
 </manifest>
diff --git a/location/tests/locationtests/AndroidTest.xml b/location/tests/locationtests/AndroidTest.xml
new file mode 100644
index 0000000..0c5b7cc
--- /dev/null
+++ b/location/tests/locationtests/AndroidTest.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2017 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<configuration description="Runs Frameworks Location API Tests.">
+    <target_preparer class="com.android.tradefed.targetprep.TestAppInstallSetup">
+        <option name="test-file-name" value="FrameworksLocationTests.apk" />
+    </target_preparer>
+
+    <option name="test-suite-tag" value="apct" />
+    <option name="test-tag" value="FrameworksLocationTests" />
+    <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+        <option name="package" value="com.android.frameworks.locationtests" />
+        <option name="runner" value="android.support.test.runner.AndroidJUnitRunner" />
+    </test>
+</configuration>
diff --git a/location/tests/locationtests/src/android/location/GnssStatusTest.java b/location/tests/locationtests/src/android/location/GnssStatusTest.java
new file mode 100644
index 0000000..79ea0d6
--- /dev/null
+++ b/location/tests/locationtests/src/android/location/GnssStatusTest.java
@@ -0,0 +1,130 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package android.location;
+
+import android.test.suitebuilder.annotation.SmallTest;
+import android.util.Log;
+import java.lang.reflect.Constructor;
+import java.util.ArrayList;
+import java.util.List;
+import junit.framework.TestCase;
+
+/**
+ * Unit tests for {@link GnssStatus}.
+ */
+@SmallTest
+public class GnssStatusTest extends TestCase {
+
+  private static final String TAG = GnssStatusTest.class.getSimpleName();
+  public void setUp() throws Exception {
+    super.setUp();
+  }
+
+  /*
+   * Create {@link GnssStatus} with default value, verify whether its fields are set correctly.
+   *
+   */
+  public void testEmptyGnssStatus() throws Exception {
+    Log.i(TAG, "testEmptyGnssStatus");
+    List<SatelliteInfo> svInfos = new ArrayList<>();
+    GnssStatus gnssStatus = createGnssStatus(svInfos);
+    verifyGnssStatus(svInfos, gnssStatus);
+  }
+
+  /*
+   * Create {@link GnssStatus} with only one satellite info, verify whether its fields are set
+   * correctly.
+   */
+  public void testOneSatelliteGnssStatus() throws Exception {
+    Log.i(TAG, "testOneSatelliteGnssStatus");
+    List<SatelliteInfo> svInfos = new ArrayList<>();
+    SatelliteInfo svInfo =
+        new SatelliteInfo(100,1, true, true, true, true, 100f, 20.3f, 45.5f, 100.23f);
+    svInfos.add(svInfo);
+    GnssStatus gnssStatus = createGnssStatus(svInfos);
+    verifyGnssStatus(svInfos, gnssStatus);
+  }
+
+  /*
+   * Create {@link GnssStatus} with multiple satellite info, verify whether its fields are set
+   * correctly.
+   */
+  public void testMultipleSatellitesGnssStatus() throws Exception {
+    Log.i(TAG, "testMultipleSatellitesGnssStatus");
+    List<SatelliteInfo> svInfos = new ArrayList<>();
+    SatelliteInfo svInfo1 =
+        new SatelliteInfo(20, 1,true, true, true, true, 10.1f, 20.3f, 45.5f, 111.23f);
+    SatelliteInfo svInfo2 =
+        new SatelliteInfo(50, 2, true, false, true, false, 20.2f, 21.3f, 46.5f, 222.23f);
+    SatelliteInfo svInfo3 =
+        new SatelliteInfo(192, 3, false, true, false, true, 30.3f, 22.3f, 47.5f, 333.23f);
+    SatelliteInfo svInfo4 =
+        new SatelliteInfo(250, 4, false, false, false, false, 40.4f, 23.3f, 48.5f, 444.23f);
+    svInfos.add(svInfo1);
+    svInfos.add(svInfo2);
+    svInfos.add(svInfo3);
+    svInfos.add(svInfo4);
+    GnssStatus gnssStatus = createGnssStatus(svInfos);
+    verifyGnssStatus(svInfos, gnssStatus);
+  }
+
+  private void verifyGnssStatus(List<SatelliteInfo> svInfos, GnssStatus gnssStatus) {
+    Log.i(TAG, String.format("Verifing {0} satellites info.",svInfos.size()));
+    assertEquals(TAG + "::SatelliteCount", svInfos.size(),
+        gnssStatus.getSatelliteCount());
+    for (int i = 0; i< svInfos.size(); i++) {
+      SatelliteInfo svInfo = svInfos.get(i);
+      assertEquals(TAG + "::Svid", svInfo.mSvid, gnssStatus.getSvid(i));
+      assertEquals(TAG + "::ConstellationType", svInfo.mConstellationType,
+          gnssStatus.getConstellationType(i));
+      assertEquals(TAG + "::Cn0DbHz", svInfo.mCn0DbHz, gnssStatus.getCn0DbHz(i));
+      assertEquals(TAG + "::Elevation", svInfo.mElevation,
+          gnssStatus.getElevationDegrees(i));
+      assertEquals(TAG + "::Azimuth", svInfo.mAzimuth, gnssStatus.getAzimuthDegrees(i));
+      assertEquals(TAG + "::CarrierFrequencyHz", svInfo.mCarrierFrequency,
+          gnssStatus.getCarrierFrequencyHz(i));
+      assertEquals(TAG + "::hasEphemerisData", svInfo.mHasEphemris,
+          gnssStatus.hasEphemerisData(i));
+      assertEquals(TAG + "::HasAlmanacData", svInfo.mHasAlmanac,
+          gnssStatus.hasAlmanacData(i));
+      assertEquals(TAG + "::UsedInFix", svInfo.mUsedInFix, gnssStatus.usedInFix(i));
+      assertEquals(TAG + "::HasCarrierFrequencyHz", svInfo.mHasCarriesFrequency,
+          gnssStatus.hasCarrierFrequencyHz(i));
+    }
+  }
+
+  private static GnssStatus createGnssStatus(List<SatelliteInfo> svInfos) throws Exception {
+    Class<?> intClass = Integer.TYPE;
+    Class<?> floatArrayClass = Class.forName("[F");
+    Class<?> intArrayClass = Class.forName("[I");
+    Class[] cArg = new Class[6];
+    cArg[0] = intClass;
+    cArg[1] = intArrayClass;
+    cArg[2] = floatArrayClass;
+    cArg[3] = floatArrayClass;
+    cArg[4] = floatArrayClass;
+    cArg[5] = floatArrayClass;
+    Constructor<GnssStatus>  ctor = GnssStatus.class.getDeclaredConstructor(cArg);
+    ctor.setAccessible(true);
+    return ctor.newInstance(svInfos.size(),
+        SatelliteInfo.getSvidWithFlagsArray(svInfos),
+        SatelliteInfo.getCn0sArray(svInfos),
+        SatelliteInfo.getElevationsArray(svInfos),
+        SatelliteInfo.getAzimuthsArray(svInfos),
+        SatelliteInfo.getCarrierFrequencyArray(svInfos));
+  }
+}
diff --git a/location/tests/locationtests/src/android/location/GpsStatusTest.java b/location/tests/locationtests/src/android/location/GpsStatusTest.java
deleted file mode 100644
index 316e88d..0000000
--- a/location/tests/locationtests/src/android/location/GpsStatusTest.java
+++ /dev/null
@@ -1,356 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package android.location;
-
-import junit.framework.TestCase;
-
-import android.test.suitebuilder.annotation.SmallTest;
-
-import java.lang.reflect.Constructor;
-import java.lang.reflect.Method;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.Random;
-import java.util.Set;
-
-/**
- * Unit tests for {@link GpsStatus}.
- */
-@SmallTest
-public class GpsStatusTest extends TestCase {
-
-    private static final int MAX_VALUE = 250;
-
-    private final Random mRandom = new Random();
-
-    private GpsStatus mStatus;
-    private int mCount;
-    private int[] mPrns;
-    private float[] mCn0s;
-    private float[] mElevations;
-    private float[] mAzimuth;
-    private int mEphemerisMask;
-    private int mAlmanacMask;
-    private int mUsedInFixMask;
-
-    public void setUp() throws Exception {
-        super.setUp();
-        mStatus = createGpsStatus();
-        generateSatellitesData(generateInt());
-    }
-
-    public void testEmptyGpsStatus() throws Exception {
-        verifyIsEmpty(mStatus);
-    }
-
-    public void testGpsStatusIterator() throws Exception {
-        generateSatellitesData(2);
-        setSatellites(mStatus);
-        Iterator<GpsSatellite> iterator = mStatus.getSatellites().iterator();
-        assertTrue("hasNext(1)", iterator.hasNext());
-        assertTrue("hasNext(1) does not overflow", iterator.hasNext());
-        GpsSatellite satellite1 = iterator.next();
-        assertNotNull("satellite", satellite1);
-        assertTrue("hasNext(2)", iterator.hasNext());
-        assertTrue("hasNext(2) does not overflow", iterator.hasNext());
-        GpsSatellite satellite2 = iterator.next();
-        assertNotNull("satellite", satellite2);
-        assertFalse("hasNext() no elements", iterator.hasNext());
-    }
-
-    public void testTtff() throws Exception {
-        int testTtff = generateInt();
-        set(mStatus, testTtff);
-        verifyTtff(mStatus, testTtff);
-    }
-
-    public void testCopyTtff() throws Exception {
-        int testTtff = generateInt();
-        verifyTtff(mStatus, 0);
-
-        GpsStatus otherStatus = createGpsStatus();
-        set(otherStatus, testTtff);
-        verifyTtff(otherStatus, testTtff);
-
-        set(mStatus, otherStatus);
-        verifyTtff(mStatus, testTtff);
-    }
-
-    public void testSetSatellites() throws Exception {
-        setSatellites(mStatus);
-        verifySatellites(mStatus);
-    }
-
-    public void testCopySatellites() throws Exception {
-        verifyIsEmpty(mStatus);
-
-        GpsStatus otherStatus = createGpsStatus();
-        setSatellites(otherStatus);
-        verifySatellites(otherStatus);
-
-        set(mStatus, otherStatus);
-        verifySatellites(mStatus);
-    }
-
-    public void testOverrideSatellites() throws Exception {
-        setSatellites(mStatus);
-        verifySatellites(mStatus);
-
-        GpsStatus otherStatus = createGpsStatus();
-        generateSatellitesData(mCount, true /* reusePrns */);
-        setSatellites(otherStatus);
-        verifySatellites(otherStatus);
-
-        set(mStatus, otherStatus);
-        verifySatellites(mStatus);
-    }
-
-    public void testAddSatellites() throws Exception {
-        int count = 10;
-        generateSatellitesData(count);
-        setSatellites(mStatus);
-        verifySatellites(mStatus);
-
-        GpsStatus otherStatus = createGpsStatus();
-        generateSatellitesData(count);
-        setSatellites(otherStatus);
-        verifySatellites(otherStatus);
-
-        set(mStatus, otherStatus);
-        verifySatellites(mStatus);
-    }
-
-    public void testAddMoreSatellites() throws Exception {
-        int count = 25;
-        generateSatellitesData(count);
-        setSatellites(mStatus);
-        verifySatellites(mStatus);
-
-        GpsStatus otherStatus = createGpsStatus();
-        generateSatellitesData(count * 2);
-        setSatellites(otherStatus);
-        verifySatellites(otherStatus);
-
-        set(mStatus, otherStatus);
-        verifySatellites(mStatus);
-    }
-
-    public void testAddLessSatellites() throws Exception {
-        int count = 25;
-        generateSatellitesData(count * 2);
-        setSatellites(mStatus);
-        verifySatellites(mStatus);
-
-        GpsStatus otherStatus = createGpsStatus();
-        generateSatellitesData(count);
-        setSatellites(otherStatus);
-        verifySatellites(otherStatus);
-
-        set(mStatus, otherStatus);
-        verifySatellites(mStatus);
-    }
-
-    private static void verifyIsEmpty(GpsStatus status) {
-        verifySatelliteCount(status, 0);
-        verifyTtff(status, 0);
-    }
-
-    private static void verifySatelliteCount(GpsStatus status, int expectedCount) {
-        int satellites = 0;
-        for (GpsSatellite s : status.getSatellites()) {
-            ++satellites;
-        }
-        assertEquals("GpsStatus::SatelliteCount", expectedCount, satellites);
-    }
-
-    private void verifySatellites(GpsStatus status) {
-        verifySatelliteCount(status, mCount);
-        verifySatellites(status, mCount, mPrns, mCn0s, mElevations, mAzimuth, mEphemerisMask,
-                mAlmanacMask, mUsedInFixMask);
-    }
-
-    private static void verifySatellites(
-            GpsStatus status,
-            int count,
-            int[] prns,
-            float[] cn0s,
-            float[] elevations,
-            float[] azimuth,
-            int ephemerisMask,
-            int almanacMask,
-            int usedInFixMask) {
-        for (int i = 0; i < count; ++i) {
-            int prn = prns[i];
-            GpsSatellite satellite = getSatellite(status, prn);
-            assertNotNull(getSatelliteAssertInfo(i, prn, "non-null"), satellite);
-            assertEquals(getSatelliteAssertInfo(i, prn, "Snr"), cn0s[i], satellite.getSnr());
-            assertEquals(
-                    getSatelliteAssertInfo(i, prn, "Elevation"),
-                    elevations[i],
-                    satellite.getElevation());
-            assertEquals(
-                    getSatelliteAssertInfo(i, prn, "Azimuth"),
-                    azimuth[i],
-                    satellite.getAzimuth());
-            int prnShift = 1 << (prn - 1);
-            assertEquals(
-                    getSatelliteAssertInfo(i, prn, "ephemeris"),
-                    (ephemerisMask & prnShift) != 0,
-                    satellite.hasEphemeris());
-            assertEquals(
-                    getSatelliteAssertInfo(i, prn, "almanac"),
-                    (almanacMask & prnShift) != 0,
-                    satellite.hasAlmanac());
-            assertEquals(
-                    getSatelliteAssertInfo(i, prn, "usedInFix"),
-                    (usedInFixMask & prnShift) != 0,
-                    satellite.usedInFix());
-        }
-    }
-
-    private static void verifyTtff(GpsStatus status, int expectedTtff) {
-        assertEquals("GpsStatus::TTFF", expectedTtff, status.getTimeToFirstFix());
-    }
-
-    private static GpsStatus createGpsStatus() throws Exception {
-        Constructor<GpsStatus>  ctor = GpsStatus.class.getDeclaredConstructor();
-        ctor.setAccessible(true);
-        return ctor.newInstance();
-    }
-
-    private static void set(GpsStatus status, int ttff) throws Exception {
-        Class<?> statusClass = status.getClass();
-        Method setTtff = statusClass.getDeclaredMethod("setTimeToFirstFix", Integer.TYPE);
-        setTtff.setAccessible(true);
-        setTtff.invoke(status, ttff);
-    }
-
-    private static void set(GpsStatus status, GpsStatus statusToSet) throws Exception {
-        Class<?> statusClass = status.getClass();
-        Method setStatus = statusClass.getDeclaredMethod("setStatus", statusClass);
-        setStatus.setAccessible(true);
-        setStatus.invoke(status, statusToSet);
-    }
-
-    private void setSatellites(GpsStatus status) throws Exception {
-        set(status, mCount, mPrns, mCn0s, mElevations, mAzimuth, mEphemerisMask, mAlmanacMask,
-                mUsedInFixMask);
-    }
-
-    private static void set(
-            GpsStatus status,
-            int count,
-            int[] prns,
-            float[] cn0s,
-            float[] elevations,
-            float[] azimuth,
-            int ephemerisMask,
-            int almanacMask,
-            int usedInFixMask) throws Exception {
-        Class<?> statusClass = status.getClass();
-        Class<?> intClass = Integer.TYPE;
-        Class<?> floatArrayClass = Class.forName("[F");
-        Method setStatus = statusClass.getDeclaredMethod(
-                "setStatus",
-                intClass,
-                Class.forName("[I"),
-                floatArrayClass,
-                floatArrayClass,
-                floatArrayClass,
-                intClass,
-                intClass,
-                intClass);
-        setStatus.setAccessible(true);
-        setStatus.invoke(
-                status,
-                count,
-                prns,
-                cn0s,
-                elevations,
-                azimuth,
-                ephemerisMask,
-                almanacMask,
-                usedInFixMask);
-    }
-
-    private int generateInt() {
-        return mRandom.nextInt(MAX_VALUE) + 1;
-    }
-
-    private int[] generateIntArray(int count) {
-        Set<Integer> generatedPrns = new HashSet<>();
-        int[] array = new int[count];
-        for(int i = 0; i < count; ++i) {
-            int generated;
-            do {
-                generated = generateInt();
-            } while (generatedPrns.contains(generated));
-            array[i] = generated;
-            generatedPrns.add(generated);
-        }
-        return array;
-    }
-
-    private float[] generateFloatArray(int count) {
-        float[] array = new float[count];
-        for(int i = 0; i < count; ++i) {
-            array[i] = generateInt();
-        }
-        return array;
-    }
-
-    private int generateMask(int[] prns) {
-        int mask = 0;
-        int prnsLength = prns.length;
-        for (int i = 0; i < prnsLength; ++i) {
-            if (mRandom.nextBoolean()) {
-                mask |= 1 << (prns[i] - 1);
-            }
-        }
-        return mask;
-    }
-
-    private void generateSatellitesData(int count) {
-        generateSatellitesData(count, false /* reusePrns */);
-    }
-
-    private void generateSatellitesData(int count, boolean reusePrns) {
-        mCount = count;
-        if (!reusePrns) {
-            mPrns = generateIntArray(count);
-        }
-        mCn0s = generateFloatArray(count);
-        mElevations = generateFloatArray(count);
-        mAzimuth = generateFloatArray(count);
-        mEphemerisMask = generateMask(mPrns);
-        mAlmanacMask = generateMask(mPrns);
-        mUsedInFixMask = generateMask(mPrns);
-    }
-
-    private static GpsSatellite getSatellite(GpsStatus status, int prn) {
-        for (GpsSatellite satellite : status.getSatellites()) {
-            if (satellite.getPrn() == prn) {
-                return satellite;
-            }
-        }
-        return null;
-    }
-
-    private static String getSatelliteAssertInfo(int index, int prn, String param) {
-        return String.format("Satellite::%s [i=%d, prn=%d]", param, index, prn);
-    }
-}
diff --git a/location/tests/locationtests/src/android/location/SatelliteInfo.java b/location/tests/locationtests/src/android/location/SatelliteInfo.java
new file mode 100644
index 0000000..b6453ef
--- /dev/null
+++ b/location/tests/locationtests/src/android/location/SatelliteInfo.java
@@ -0,0 +1,155 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package android.location;
+
+import java.util.List;
+
+/*
+ * Helper class to store single Satellite info, only used it in the unit test.
+ */
+public class SatelliteInfo {
+  private static final int SVID_MAX_BIT_INDEX = 32;
+  private static final int SVID_SHIFT_WIDTH = 8;
+  private static final int CONSTELLATION_TYPE_SHIFT_WIDTH = 4;
+
+  // Index for the bits in mSvidWithFlag
+  private static final int GNSS_SV_FLAGS_HAS_EPHEMERIS_DATA_BIT_INDEX = 0;
+  private static final int GNSS_SV_FLAGS_HAS_ALMANAC_DATA_BIT_INDEX = 1;
+  private static final int GNSS_SV_FLAGS_USED_IN_FIX_BIT_INDEX = 2;
+  private static final int GNSS_SV_FLAGS_HAS_CARRIER_FREQUENCY_BIT_INDEX = 3;
+  public int mSvid;
+  public int mSvidWithFlag;
+  public float mCn0DbHz;
+  public float mElevation;
+  public float mAzimuth;
+  public float mCarrierFrequency;
+
+  /*
+   * Flag fields, it stores the same information as svidWithFlag, but in different format, easy for
+   * the unit test.
+   */
+  public int mConstellationType;
+  public boolean mHasEphemris;
+  public boolean mHasAlmanac;
+  public boolean mUsedInFix;
+  public boolean mHasCarriesFrequency;
+
+  public SatelliteInfo(int svid, int constellationType, boolean hasEphemris, boolean hasAlmanac,
+      boolean usedInFix, boolean hasCarriesFrequency, float cn0, float elevation, float azimuth,
+      float carrierFrequency) {
+    mSvidWithFlag =
+        setRange(mSvidWithFlag, constellationType, CONSTELLATION_TYPE_SHIFT_WIDTH, SVID_SHIFT_WIDTH);
+    mSvidWithFlag = setRange(mSvidWithFlag, svid, SVID_SHIFT_WIDTH, SVID_MAX_BIT_INDEX);
+    mSvidWithFlag = setBit(mSvidWithFlag, hasEphemris, GNSS_SV_FLAGS_HAS_EPHEMERIS_DATA_BIT_INDEX);
+    mSvidWithFlag = setBit(mSvidWithFlag, hasAlmanac, GNSS_SV_FLAGS_HAS_ALMANAC_DATA_BIT_INDEX);
+    mSvidWithFlag = setBit(mSvidWithFlag, usedInFix, GNSS_SV_FLAGS_USED_IN_FIX_BIT_INDEX);
+    mSvidWithFlag =
+        setBit(mSvidWithFlag, hasCarriesFrequency, GNSS_SV_FLAGS_HAS_CARRIER_FREQUENCY_BIT_INDEX);
+    this.mSvid = svid;
+    this.mConstellationType = constellationType;
+    this.mCn0DbHz = cn0;
+    this.mElevation = elevation;
+    this.mAzimuth = azimuth;
+    this.mCarrierFrequency = carrierFrequency;
+    this.mHasEphemris = hasEphemris;
+    this.mHasAlmanac = hasAlmanac;
+    this.mUsedInFix = usedInFix;
+    this.mHasCarriesFrequency = hasCarriesFrequency;
+  }
+
+  /*
+   * Gernerate svidWithFlags array from svInfos
+   */
+  public static int[] getSvidWithFlagsArray(List<SatelliteInfo> svInfos) {
+    int[] svidWithFlags = new int[svInfos.size()];
+    for (int i = 0; i< svInfos.size(); i++) {
+      svidWithFlags[i] = svInfos.get(i).mSvidWithFlag;
+    }
+    return svidWithFlags;
+  }
+
+  /*
+   * Gernerate cn0s array from svInfos
+   */
+  public static float[] getCn0sArray(List<SatelliteInfo> svInfos) {
+    float[] cn0s = new float[svInfos.size()];
+    for (int i = 0; i< svInfos.size(); i++) {
+      cn0s[i] = svInfos.get(i).mCn0DbHz;
+    }
+    return cn0s;
+  }
+
+  /*
+   * Gernerate elevations array from svInfos
+   */
+  public static float[] getElevationsArray(List<SatelliteInfo> svInfos) {
+    float[] elevations = new float[svInfos.size()];
+    for (int i = 0; i< svInfos.size(); i++) {
+      elevations[i] = svInfos.get(i).mElevation;
+    }
+    return elevations;
+  }
+
+  /*
+   * Gernerate azimuths array from svInfos
+   */
+  public static float[] getAzimuthsArray(List<SatelliteInfo> svInfos) {
+    float[] azimuths = new float[svInfos.size()];
+    for (int i = 0; i< svInfos.size(); i++) {
+      azimuths[i] = svInfos.get(i).mAzimuth;
+    }
+    return azimuths;
+  }
+
+  /*
+   * Gernerate carrierFrequency array from svInfos
+   */
+  public static float[] getCarrierFrequencyArray(List<SatelliteInfo> svInfos) {
+    float[] carrierFrequencies = new float[svInfos.size()];
+    for (int i = 0; i< svInfos.size(); i++) {
+      carrierFrequencies[i] = svInfos.get(i).mCarrierFrequency;
+    }
+    return carrierFrequencies;
+  }
+
+  private int setBit(int targetValue, boolean value, int index) {
+    if (value) {
+      targetValue = targetValue | (1 << index);
+    } else {
+      targetValue = targetValue & ~(1 << index);
+    }
+    return targetValue;
+  }
+
+  /*
+   * Set the bit in the range [fromIndex, toIndex), index start from the lowest bit.
+   * value -> 1 1 0 1 1 0 1 0
+   * index -> 7 6 5 4 3 2 1 0
+   * This function will set the bit in the range to the lowest X bits of the value.
+   */
+  private int setRange(int targetValue, int value, int fromIndex, int toIndex) {
+    int rangeLen = toIndex - fromIndex;
+    int valueMask = (1 << rangeLen) -1;
+    value &= valueMask;
+    value = value << fromIndex;
+    valueMask = valueMask << fromIndex;
+    targetValue &= (~valueMask);
+    targetValue |= value;
+    return targetValue;
+  }
+
+}
\ No newline at end of file