Merge "Limit Carrier Privileges to relevant CTS test app" into emu-master-dev
diff --git a/android/android-emu/android/telephony/SimAccessRules.cpp b/android/android-emu/android/telephony/SimAccessRules.cpp
index b470043..37a96a0 100644
--- a/android/android-emu/android/telephony/SimAccessRules.cpp
+++ b/android/android-emu/android/telephony/SimAccessRules.cpp
@@ -27,8 +27,8 @@
 static AllRefArDo kCtsAppCertificateHash {
     RefArDo {
         RefDo {
-            AidRefDo {},
-            DeviceAppIdRefDo { "61ed377e85d386a8dfee6b864bd85b0bfaa5af81" }
+            DeviceAppIdRefDo { "61ed377e85d386a8dfee6b864bd85b0bfaa5af81" },
+            PkgRefDo { "android.carrierapi.cts" }
         },
         ArDo {
             PermArDo { "0000000000000000" }
diff --git a/android/android-emu/android/telephony/TagLengthValue.cpp b/android/android-emu/android/telephony/TagLengthValue.cpp
index 17fd34b..3a38d88 100644
--- a/android/android-emu/android/telephony/TagLengthValue.cpp
+++ b/android/android-emu/android/telephony/TagLengthValue.cpp
@@ -11,6 +11,8 @@
 */
 #include "TagLengthValue.h"
 
+#include "android/utils/misc.h"
+
 #include <assert.h>
 #include <vector>
 #include <stdint.h>
@@ -30,6 +32,17 @@
 // Size: 0x12345, String: "83012345" -- 83 indicates 3 bytes needed, zero padded
 static const uint32_t kMaxSingleByteSize = 0x80;
 
+// Convert a plain string to a string of hexadecimal values representing the
+// value of each character of the plain string. For example the string "FOO"
+// will be converted to "464F4F".
+static std::string stringToHexString(const std::string& str) {
+    std::string result(str.size() * 2, '0');
+    for (size_t i = 0; i < str.size(); ++i) {
+        int2hex(reinterpret_cast<uint8_t*>(&result[i * 2]), 2, str[i]);
+    }
+    return result;
+}
+
 void TagLengthValue::populateData(const char* tag,
         std::initializer_list<const TagLengthValue*> data) {
     populateData(tag, data.begin(), data.end());
@@ -89,6 +102,7 @@
 }
 
 const char AidRefDo::kTag[] = "4F";
+const char PkgRefDo::kTag[] = "CA";
 const char DeviceAppIdRefDo::kTag[] = "C1";
 const char RefDo::kTag[] = "E1";
 const char ApduArDo::kTag[] = "D0";
@@ -98,15 +112,29 @@
 const char RefArDo::kTag[] = "E2";
 const char AllRefArDo::kTag[] = "FF40";
 
+PkgRefDo::PkgRefDo(const std::string& packageName) {
+    std::string hexPackageName = stringToHexString(packageName);
+    populateData(kTag, { &hexPackageName });
+}
+
 DeviceAppIdRefDo::DeviceAppIdRefDo(const std::string& stringData) {
     populateData(kTag, { &stringData });
 }
 
+RefDo::RefDo(const DeviceAppIdRefDo& deviceAppIdRefDo) {
+    populateData(kTag, { &deviceAppIdRefDo });
+}
+
 RefDo::RefDo(const AidRefDo& aidRefDo,
              const DeviceAppIdRefDo& deviceAppIdRefDo) {
     populateData(kTag, { &aidRefDo, &deviceAppIdRefDo });
 }
 
+RefDo::RefDo(const DeviceAppIdRefDo& deviceAppIdRefDo,
+             const PkgRefDo& pkgRefDo) {
+    populateData(kTag, { &deviceAppIdRefDo, &pkgRefDo });
+}
+
 ApduArDo::ApduArDo(Allow rule) {
     // Allocate enough space for the data plus NULL, then resize down to 2 to
     // avoid modifying the terminating NULL (which is undefined behavior)
diff --git a/android/android-emu/android/telephony/TagLengthValue.h b/android/android-emu/android/telephony/TagLengthValue.h
index 7f5e625..93bc789 100644
--- a/android/android-emu/android/telephony/TagLengthValue.h
+++ b/android/android-emu/android/telephony/TagLengthValue.h
@@ -60,6 +60,15 @@
     static const char kTag[];
 };
 
+// PKG-REF-DO, contains a package name string identifying a particular
+// application. If a package name is present the access rule only applies to the
+// package matching this name
+class PkgRefDo : public TagLengthValue {
+    static const char kTag[];
+public:
+    explicit PkgRefDo(const std::string& packageName);
+};
+
 // DeviceAppID-REF-DO, contains a unique app ID or hash of a certificate used
 // to sign an app.
 class DeviceAppIdRefDo : public TagLengthValue {
@@ -69,12 +78,17 @@
     explicit DeviceAppIdRefDo(const std::string& stringData);
 };
 
-// REF-DO, Reference Data Object, contains an AID reference and DeviceAppID
-// reference that together uniquely identify an application
+// REF-DO, Reference Data Object, contains a DeviceAppID reference and
+// optionally either an AidRefDo or a PkgRefDo. This uniquely identifies an
+// application.
 class RefDo : public TagLengthValue {
     static const char kTag[];
 public:
-    RefDo(const AidRefDo& aidRefDo, const DeviceAppIdRefDo& deviceAppIdRefDo);
+    explicit RefDo(const DeviceAppIdRefDo& deviceAppIdRefDo);
+    RefDo(const AidRefDo& aidRefDo,
+          const DeviceAppIdRefDo& deviceAppIdRefDo);
+    RefDo(const DeviceAppIdRefDo& deviceAppIdRefDo,
+          const PkgRefDo& pkgRefDo);
 };
 
 // APDU-AR-DO, used to set access rules regarding APDU commands, can be used to
diff --git a/android/android-emu/android/telephony/TagLengthValue_unittest.cpp b/android/android-emu/android/telephony/TagLengthValue_unittest.cpp
index 480ec4d..d9d7aa6 100644
--- a/android/android-emu/android/telephony/TagLengthValue_unittest.cpp
+++ b/android/android-emu/android/telephony/TagLengthValue_unittest.cpp
@@ -24,8 +24,23 @@
                  deviceAppIdRefDo.c_str());
 }
 
+TEST(TagLengthValue, ConstructPkgRefDo) {
+    PkgRefDo pkgRefDo("com.android.foo");
+
+    ASSERT_STREQ(/*tag*/ "CA" /*length*/ "0f"
+                 /*payload*/ "636f6d2e616e64726f69642e666f6f",
+                 pkgRefDo.c_str());
+}
+
 TEST(TagLengthValue, ConstructRefDo) {
-    RefDo refDo(AidRefDo(), DeviceAppIdRefDo("C0FFEE"));
+    RefDo refDo{DeviceAppIdRefDo("C0FFEE")};
+
+    ASSERT_STREQ(/*tag*/ "E1" /*length*/ "05" /*payload*/ "C103C0FFEE",
+                 refDo.c_str());
+}
+
+TEST(TagLengthValue, ConstructRefDoWithAidRefDo) {
+    RefDo refDo{AidRefDo(), DeviceAppIdRefDo("C0FFEE")};
 
     // Note that the AID-REF-DO does not end up in the payload because we
     // construct an empty object.
@@ -33,6 +48,14 @@
                  refDo.c_str());
 }
 
+TEST(TagLengthValue, ConstructRefDoWithPkgRefDo) {
+    RefDo refDo{DeviceAppIdRefDo("C0FFEE"), PkgRefDo("foo")};
+
+    ASSERT_STREQ(/*tag*/ "E1" /*length*/ "0a"
+                 /*payload*/ "C103C0FFEECA03666f6f",
+                 refDo.c_str());
+}
+
 TEST(TagLengthValue, ConstructApduArDo) {
     ApduArDo globalDenyRule(ApduArDo::Allow::Never);
     ASSERT_STREQ(/*tag*/ "D0" /*length*/ "01" /*payload*/ "00",
diff --git a/android/android-emu/android/telephony/modem_unittest.cpp b/android/android-emu/android/telephony/modem_unittest.cpp
index 7d69d63..12cad11 100644
--- a/android/android-emu/android/telephony/modem_unittest.cpp
+++ b/android/android-emu/android/telephony/modem_unittest.cpp
@@ -101,7 +101,7 @@
     ASSERT_FALSE(closeLogicalChannel(channel));
 }
 
-static const char* kValidReply = "+CGLA: 144,0,FF4026E224E116C11461ed377e85d386a8dfee6b864bd85b0bfaa5af81E30aDB080000000000000000\rOK";
+static const char* kValidReply = "+CGLA: 144,0,FF403eE23cE12eC11461ed377e85d386a8dfee6b864bd85b0bfaa5af81CA16616e64726f69642e636172726965726170692e637473E30aDB080000000000000000\rOK";
 static const char* kCmeError = "+CME ERROR: ";
 
 TEST_F(ModemTest, TransmitLogicalChannel) {