Add default power policy group id

Add support for defining default power policy
group id via xml.

Bug: 243754875
Test: atest PolicyReaderUnitTest PolicyManagerTest CarPowerPolicyServerTest
Change-Id: I3864c77178c660093727961d3659f473649a4abc
(cherry picked from commit 4b2d17f5bb1720249be0c1b1bb2195badca7041f)
Merged-In: I3864c77178c660093727961d3659f473649a4abc
diff --git a/cpp/powerpolicy/server/src/CarPowerPolicyServer.cpp b/cpp/powerpolicy/server/src/CarPowerPolicyServer.cpp
index bac712a..c6746af 100644
--- a/cpp/powerpolicy/server/src/CarPowerPolicyServer.cpp
+++ b/cpp/powerpolicy/server/src/CarPowerPolicyServer.cpp
@@ -713,6 +713,7 @@
         !ret.ok()) {
         ALOGW("Cannot apply the initial power policy(%s): %s", policyId.c_str(),
               ret.error().message().c_str());
+        return;
     }
     ALOGD("Policy(%s) is applied as the initial one", policyId.c_str());
 }
diff --git a/cpp/powerpolicy/server/src/PolicyManager.cpp b/cpp/powerpolicy/server/src/PolicyManager.cpp
index 33a8f80..6100056 100644
--- a/cpp/powerpolicy/server/src/PolicyManager.cpp
+++ b/cpp/powerpolicy/server/src/PolicyManager.cpp
@@ -15,6 +15,7 @@
  */
 
 #define LOG_TAG "carpowerpolicyd"
+#define DEBUG false  // STOPSHIP if true.
 
 #include "PolicyManager.h"
 
@@ -66,6 +67,7 @@
 constexpr const char kAttrBehavior[] = "behavior";
 constexpr const char kAttrId[] = "id";
 constexpr const char kAttrState[] = "state";
+constexpr const char kAttrDefaultPolicyGroup[] = "defaultPolicyGroup";
 
 // Power states.
 constexpr const char kPowerStateOn[] = "on";
@@ -324,14 +326,27 @@
     return policyGroup;
 }
 
-Result<std::unordered_map<std::string, PolicyGroup>> readPolicyGroups(
+struct PolicyGroups {
+    std::unordered_map<std::string, PolicyGroup> groups;
+    std::string defaultGroup;
+};
+
+Result<PolicyGroups> readPolicyGroups(
         const XMLElement* pRoot,
         const std::unordered_map<std::string, CarPowerPolicyPtr>& registeredPowerPolicies) {
     const XMLElement* pPolicyGroups = pRoot->FirstChildElement(kTagPolicyGroups);
+
+    PolicyGroups policyGroups;
+
     if (pPolicyGroups == nullptr) {
-        return std::unordered_map<std::string, PolicyGroup>();
+        return policyGroups;
     }
-    std::unordered_map<std::string, PolicyGroup> policyGroups;
+
+    const char* pDefaultPolicyGroupId = nullptr;
+    pPolicyGroups->QueryStringAttribute(kAttrDefaultPolicyGroup, &pDefaultPolicyGroupId);
+    if (pDefaultPolicyGroupId != nullptr) {
+        policyGroups.defaultGroup = pDefaultPolicyGroupId;
+    }
 
     for (const XMLElement* pPolicyGroup = pPolicyGroups->FirstChildElement(kTagPolicyGroup);
          pPolicyGroup != nullptr;
@@ -345,7 +360,7 @@
         if (!policyGroup.ok()) {
             return Error() << policyGroup.error();
         }
-        policyGroups.emplace(policyGroupId, *policyGroup);
+        policyGroups.groups.emplace(policyGroupId, *policyGroup);
     }
     return policyGroups;
 }
@@ -475,10 +490,13 @@
 
 Result<CarPowerPolicyPtr> PolicyManager::getDefaultPowerPolicyForState(
         const std::string& groupId, VehicleApPowerStateReport state) const {
-    if (mPolicyGroups.count(groupId) == 0) {
-        return Error() << StringPrintf("Power policy group(%s) is not available", groupId.c_str());
+    auto groupIdToUse = groupId.empty() ? mDefaultPolicyGroup : groupId;
+
+    if (mPolicyGroups.count(groupIdToUse) == 0) {
+        return Error() << StringPrintf("Power policy group %s is not found", groupIdToUse.c_str());
     }
-    PolicyGroup policyGroup = mPolicyGroups.at(groupId);
+
+    PolicyGroup policyGroup = mPolicyGroups.at(groupIdToUse);
     int32_t key = static_cast<int32_t>(state);
     if (policyGroup.count(key) == 0) {
         return Error() << StringPrintf("Policy for %s is not found", toString(state).c_str());
@@ -572,6 +590,7 @@
     for (auto policy : *registeredPolicies) {
         registeredPoliciesMap.emplace(policy->policyId, policy);
     }
+
     const auto& policyGroups = readPolicyGroups(pRootElement, registeredPoliciesMap);
     if (!policyGroups.ok()) {
         logXmlError(StringPrintf("Reading power policy groups for power state failed: %s",
@@ -587,7 +606,8 @@
 
     mRegisteredPowerPolicies = registeredPoliciesMap;
     initRegularPowerPolicy(/*override=*/false);
-    mPolicyGroups = *policyGroups;
+    mPolicyGroups = policyGroups->groups;
+    mDefaultPolicyGroup = policyGroups->defaultGroup;
     reconstructNoUserInteractionPolicy(*systemPolicyOverrides);
 }
 
@@ -633,6 +653,10 @@
                                                   kSuspendPrepDisabledComponents));
 }
 
+std::string PolicyManager::getDefaultPolicyGroup() const {
+    return mDefaultPolicyGroup;
+}
+
 }  // namespace powerpolicy
 }  // namespace automotive
 }  // namespace frameworks
diff --git a/cpp/powerpolicy/server/src/PolicyManager.h b/cpp/powerpolicy/server/src/PolicyManager.h
index 956fa1a..fe5ed50 100644
--- a/cpp/powerpolicy/server/src/PolicyManager.h
+++ b/cpp/powerpolicy/server/src/PolicyManager.h
@@ -83,6 +83,7 @@
             const std::string& policyId, const std::vector<std::string>& enabledComponents,
             const std::vector<std::string>& disabledComponents);
     android::base::Result<void> dump(int fd, const android::Vector<String16>& args);
+    std::string getDefaultPolicyGroup() const;
 
 private:
     void initRegularPowerPolicy(bool override);
@@ -95,6 +96,7 @@
     std::unordered_map<std::string, CarPowerPolicyPtr> mRegisteredPowerPolicies;
     std::unordered_map<std::string, CarPowerPolicyPtr> mPreemptivePowerPolicies;
     std::unordered_map<std::string, PolicyGroup> mPolicyGroups;
+    std::string mDefaultPolicyGroup;
 
     // For unit tests.
     friend class internal::PolicyManagerPeer;
diff --git a/cpp/powerpolicy/server/tests/PolicyManagerTest.cpp b/cpp/powerpolicy/server/tests/PolicyManagerTest.cpp
index 0c5b332..ad61627 100644
--- a/cpp/powerpolicy/server/tests/PolicyManagerTest.cpp
+++ b/cpp/powerpolicy/server/tests/PolicyManagerTest.cpp
@@ -46,10 +46,15 @@
         "valid_power_policy_policies_only.xml";
 constexpr const char* kValidPowerPolicySystemPowerPolicyOnlyXmlFile =
         "valid_power_policy_system_power_policy_only.xml";
+constexpr const char* kValidPowerPolicyWithDefaultPolicyGroup =
+        "valid_power_policy_default_policy_group.xml";
+constexpr const char* kValidPowerPolicyWithInvalidDefaultPolicyGroup =
+        "invalid_system_power_policy_incorrect_default_power_policy_group_id.xml";
 const std::vector<const char*> kInvalidPowerPolicyXmlFiles =
         {"invalid_power_policy_incorrect_id.xml",
          "invalid_power_policy_incorrect_othercomponent.xml",
-         "invalid_power_policy_incorrect_value.xml", "invalid_power_policy_unknown_component.xml"};
+         "invalid_power_policy_incorrect_value.xml", "invalid_power_policy_unknown_component.xml",
+         "invalid_system_power_policy_incorrect_default_power_policy_group_id.xml"};
 const std::vector<const char*> kInvalidPowerPolicyGroupXmlFiles =
         {"invalid_power_policy_group_incorrect_state.xml",
          "invalid_power_policy_group_missing_policy.xml"};
@@ -69,6 +74,7 @@
 constexpr const char* kSystemPolicyIdInitialOn = "system_power_policy_initial_on";
 constexpr const char* kSystemPolicyIdInitialAllOn = "system_power_policy_all_on";
 constexpr const char* kSystemPolicyIdSuspendPrep = "system_power_policy_suspend_prep";
+constexpr const char* kMixedPolicyGroupName = "mixed_policy_group";
 
 const VehicleApPowerStateReport kExistingTransition = VehicleApPowerStateReport::WAIT_FOR_VHAL;
 const VehicleApPowerStateReport kNonExistingTransition = static_cast<VehicleApPowerStateReport>(-1);
@@ -346,6 +352,27 @@
     checkSystemPowerPolicy(policyManager, kModifiedSystemPowerPolicy);
 }
 
+TEST_F(PolicyManagerTest, TestValidXml_TestDefaultPowerPolicyGroupId) {
+    PolicyManager policyManager;
+    internal::PolicyManagerPeer policyManagerPeer(&policyManager);
+    policyManagerPeer.expectValidPowerPolicyXML(kValidPowerPolicyWithDefaultPolicyGroup);
+
+    ASSERT_TRUE(policyManager.getDefaultPolicyGroup() == kMixedPolicyGroupName);
+}
+
+TEST_F(PolicyManagerTest, TestValidXml_TestInvalidDefaultPowerPolicyGroupId) {
+    PolicyManager policyManager;
+    internal::PolicyManagerPeer policyManagerPeer(&policyManager);
+    policyManagerPeer.expectValidPowerPolicyXML(kValidPowerPolicyWithInvalidDefaultPolicyGroup);
+
+    ASSERT_EQ(policyManager.getDefaultPolicyGroup(), "");
+
+    ASSERT_FALSE(
+            policyManager
+                    .getDefaultPowerPolicyForState(kInvalidPowerPolicyGroupId, kExistingTransition)
+                    .ok());
+}
+
 TEST_F(PolicyManagerTest, TestDefaultPowerPolicies) {
     PolicyManager policyManager;
     internal::PolicyManagerPeer policyManagerPeer(&policyManager);
diff --git a/cpp/powerpolicy/server/tests/data/invalid_system_power_policy_incorrect_default_power_policy_group_id.xml b/cpp/powerpolicy/server/tests/data/invalid_system_power_policy_incorrect_default_power_policy_group_id.xml
new file mode 100644
index 0000000..4c1b161
--- /dev/null
+++ b/cpp/powerpolicy/server/tests/data/invalid_system_power_policy_incorrect_default_power_policy_group_id.xml
@@ -0,0 +1,38 @@
+<?xml version='1.0' encoding='utf-8'?>
+<!-- Copyright (C) 2022 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.
+-->
+
+<powerPolicy version="1.0">
+
+    <policyGroups defaultPolicyGroup="someGroup">
+        <policyGroup id="mixed_policy_group">
+            <defaultPolicy state="WaitForVHAL" id="expected_to_be_registered"/>
+        </policyGroup>
+    </policyGroups>
+
+    <policies>
+        <policy id="expected_to_be_registered">
+            <otherComponents behavior="on"/>
+        </policy>
+    </policies>
+
+    <systemPolicyOverrides>
+        <policy id="system_power_policy_incorrect_id">
+            <component id="POWER_COMPONENT_NFC">on</component>
+            <component id="POWER_COMPONENT_TRUSTED_DEVICE_DETECTION">off</component>
+        </policy>
+    </systemPolicyOverrides>
+
+</powerPolicy>
diff --git a/cpp/powerpolicy/server/tests/data/valid_power_policy_default_policy_group.xml b/cpp/powerpolicy/server/tests/data/valid_power_policy_default_policy_group.xml
new file mode 100644
index 0000000..89d1508
--- /dev/null
+++ b/cpp/powerpolicy/server/tests/data/valid_power_policy_default_policy_group.xml
@@ -0,0 +1,80 @@
+<?xml version='1.0' encoding='utf-8'?>
+<!-- Copyright (C) 2022 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.
+-->
+
+<powerPolicy version="1.0">
+
+    <policyGroups defaultPolicyGroup="mixed_policy_group">
+        <policyGroup id="basic_policy_group">
+            <defaultPolicy state="WaitForVHAL" id="policy_id_other_on"/>
+            <defaultPolicy state="On" id="policy_id_other_untouched"/>
+        </policyGroup>
+        <policyGroup id="no_default_policy_group">
+            <noDefaultPolicy state="WaitForVHAL"/>
+            <noDefaultPolicy state="On"/>
+        </policyGroup>
+        <policyGroup id="mixed_policy_group">
+            <defaultPolicy state="WaitForVHAL" id="policy_id_other_on"/>
+            <noDefaultPolicy state="On"/>
+        </policyGroup>
+    </policyGroups>
+
+    <policies>
+        <policy id="expected_to_be_registered">
+            <otherComponents behavior="on"/>
+        </policy>
+        <policy id="policy_id_other_off">
+            <otherComponents behavior="off"/>
+            <component id="POWER_COMPONENT_AUDIO">off</component>
+            <component id="POWER_COMPONENT_DISPLAY">off</component>
+            <component id="POWER_COMPONENT_WIFI">on</component>
+            <component id="POWER_COMPONENT_VISUAL_INTERACTION">off</component>
+            <component id="POWER_COMPONENT_TRUSTED_DEVICE_DETECTION">off</component>
+        </policy>
+        <policy id="policy_id_other_untouched">
+            <otherComponents behavior="untouched"/>
+            <component id="POWER_COMPONENT_AUDIO">on</component>
+            <component id="POWER_COMPONENT_DISPLAY">on</component>
+            <component id="POWER_COMPONENT_BLUETOOTH">on</component>
+            <component id="POWER_COMPONENT_WIFI">on</component>
+            <component id="POWER_COMPONENT_VOICE_INTERACTION">on</component>
+            <component id="POWER_COMPONENT_VISUAL_INTERACTION">on</component>
+            <component id="POWER_COMPONENT_TRUSTED_DEVICE_DETECTION">on</component>
+        </policy>
+        <policy id="policy_id_other_on">
+            <otherComponents behavior="on"/>
+            <component id="POWER_COMPONENT_AUDIO">off</component>
+            <component id="POWER_COMPONENT_VOICE_INTERACTION">off</component>
+            <component id="POWER_COMPONENT_VISUAL_INTERACTION">off</component>
+            <component id="POWER_COMPONENT_TRUSTED_DEVICE_DETECTION">off</component>
+        </policy>
+        <policy id="policy_id_other_none">
+            <component id="POWER_COMPONENT_AUDIO">off</component>
+            <component id="POWER_COMPONENT_WIFI">on</component>
+            <component id="POWER_COMPONENT_VOICE_INTERACTION">off</component>
+            <component id="POWER_COMPONENT_VISUAL_INTERACTION">off</component>
+            <component id="POWER_COMPONENT_TRUSTED_DEVICE_DETECTION">off</component>
+        </policy>
+    </policies>
+
+    <systemPolicyOverrides>
+        <policy id="system_power_policy_no_user_interaction">
+            <component id="POWER_COMPONENT_BLUETOOTH">on</component>
+            <component id="POWER_COMPONENT_NFC">on</component>
+            <component id="POWER_COMPONENT_TRUSTED_DEVICE_DETECTION">off</component>
+        </policy>
+    </systemPolicyOverrides>
+
+</powerPolicy>
diff --git a/service/src/com/android/car/power/PolicyReader.java b/service/src/com/android/car/power/PolicyReader.java
index 9a2e9f3..2fb792c 100644
--- a/service/src/com/android/car/power/PolicyReader.java
+++ b/service/src/com/android/car/power/PolicyReader.java
@@ -36,6 +36,7 @@
 import android.hardware.automotive.vehicle.VehicleApPowerStateReport;
 import android.util.ArrayMap;
 import android.util.ArraySet;
+import android.util.Log;
 import android.util.SparseArray;
 import android.util.SparseBooleanArray;
 import android.util.Xml;
@@ -98,6 +99,7 @@
     private static final String TAG_OTHER_COMPONENTS = "otherComponents";
     private static final String TAG_COMPONENT = "component";
     private static final String TAG_SYSTEM_POLICY_OVERRIDES = "systemPolicyOverrides";
+    private static final String ATTR_DEFAULT_POLICY_GROUP = "defaultPolicyGroup";
     private static final String ATTR_VERSION = "version";
     private static final String ATTR_ID = "id";
     private static final String ATTR_STATE = "state";
@@ -155,6 +157,7 @@
     private ArrayMap<String, CarPowerPolicy> mRegisteredPowerPolicies;
     private ArrayMap<String, SparseArray<String>> mPolicyGroups;
     private ArrayMap<String, CarPowerPolicy> mPreemptivePowerPolicies;
+    private String mDefaultPolicyGroupId;
 
     /**
      * Gets {@code CarPowerPolicy} corresponding to the given policy ID.
@@ -170,7 +173,8 @@
      */
     @Nullable
     CarPowerPolicy getDefaultPowerPolicyForState(String groupId, int state) {
-        SparseArray<String> group = mPolicyGroups.get(groupId);
+        SparseArray<String> group = mPolicyGroups.get(
+                (groupId == null || groupId.isEmpty()) ? mDefaultPolicyGroupId : groupId);
         if (group == null) {
             return null;
         }
@@ -200,6 +204,16 @@
         return mPreemptivePowerPolicies.containsKey(policyId);
     }
 
+    /**
+     * Gets default power policy group ID.
+     *
+     * @return {@code String} containing power policy group ID or {@code null} if it is not defined
+     */
+    @Nullable
+    String getDefaultPowerPolicyGroup() {
+        return mDefaultPolicyGroupId;
+    }
+
     void init() {
         initPolicies();
         readPowerPolicyConfiguration();
@@ -346,6 +360,7 @@
         ArrayMap<String, CarPowerPolicy> registeredPolicies = new ArrayMap<>();
         ArrayMap<String, SparseArray<String>> policyGroups = new ArrayMap<>();
         CarPowerPolicy systemPolicyOverride = null;
+        String defaultGroupPolicyId = null;
 
         int type;
         while ((type = parser.next()) != END_DOCUMENT && type != END_TAG) {
@@ -355,6 +370,8 @@
                     registeredPolicies = parsePolicies(parser, true);
                     break;
                 case TAG_POLICY_GROUPS:
+                    defaultGroupPolicyId = parser.getAttributeValue(NAMESPACE,
+                            ATTR_DEFAULT_POLICY_GROUP);
                     policyGroups = parsePolicyGroups(parser);
                     break;
                 case TAG_SYSTEM_POLICY_OVERRIDES:
@@ -365,8 +382,9 @@
                             + TAG_POWER_POLICY);
             }
         }
-        validatePolicyGroups(policyGroups, registeredPolicies);
+        validatePolicyGroups(policyGroups, registeredPolicies, defaultGroupPolicyId);
 
+        mDefaultPolicyGroupId = defaultGroupPolicyId;
         mRegisteredPowerPolicies = registeredPolicies;
         registerBasicPowerPolicies();
         mPolicyGroups = policyGroups;
@@ -576,7 +594,8 @@
     }
 
     private void validatePolicyGroups(ArrayMap<String, SparseArray<String>> policyGroups,
-            ArrayMap<String, CarPowerPolicy> registeredPolicies) throws PolicyXmlException {
+            ArrayMap<String, CarPowerPolicy> registeredPolicies, String defaultGroupPolicyId)
+            throws PolicyXmlException {
         for (Map.Entry<String, SparseArray<String>> entry : policyGroups.entrySet()) {
             SparseArray<String> group = entry.getValue();
             for (int i = 0; i < group.size(); i++) {
@@ -587,6 +606,16 @@
                 }
             }
         }
+
+        if ((defaultGroupPolicyId == null || defaultGroupPolicyId.isEmpty())
+                && !policyGroups.isEmpty()) {
+            Log.w(TAG, "No defaultGroupPolicyId is defined");
+        }
+
+        if (defaultGroupPolicyId != null && !policyGroups.containsKey(defaultGroupPolicyId)) {
+            throw new PolicyXmlException(
+                    "defaultGroupPolicyId is defined, but group with this ID doesn't exist ");
+        }
     }
 
     private void reconstructSystemPowerPolicy(@Nullable CarPowerPolicy policyOverride) {
diff --git a/tests/carservice_unit_test/res/raw/invalid_system_power_policy_incorrect_default_power_policy_group_id.xml b/tests/carservice_unit_test/res/raw/invalid_system_power_policy_incorrect_default_power_policy_group_id.xml
new file mode 100644
index 0000000..b9dd072
--- /dev/null
+++ b/tests/carservice_unit_test/res/raw/invalid_system_power_policy_incorrect_default_power_policy_group_id.xml
@@ -0,0 +1,38 @@
+<?xml version='1.0' encoding='utf-8'?>
+<!-- Copyright (C) 2021 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.
+-->
+
+<powerPolicy version="1.0">
+
+    <policyGroups defaultPolicyGroup="someGroup">
+        <policyGroup id="mixed_policy_group">
+            <defaultPolicy state="WaitForVHAL" id="expected_to_be_registered"/>
+        </policyGroup>
+    </policyGroups>
+
+    <policies>
+        <policy id="expected_to_be_registered">
+            <otherComponents behavior="on"/>
+        </policy>
+    </policies>
+
+    <systemPolicyOverrides>
+        <policy id="system_power_policy_incorrect_id">
+            <component id="POWER_COMPONENT_NFC">on</component>
+            <component id="POWER_COMPONENT_TRUSTED_DEVICE_DETECTION">off</component>
+        </policy>
+    </systemPolicyOverrides>
+
+</powerPolicy>
diff --git a/tests/carservice_unit_test/res/raw/valid_power_policy_default_policy_group.xml b/tests/carservice_unit_test/res/raw/valid_power_policy_default_policy_group.xml
new file mode 100644
index 0000000..76cc501
--- /dev/null
+++ b/tests/carservice_unit_test/res/raw/valid_power_policy_default_policy_group.xml
@@ -0,0 +1,80 @@
+<?xml version='1.0' encoding='utf-8'?>
+<!-- Copyright (C) 2021 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.
+-->
+
+<powerPolicy version="1.0">
+
+    <policyGroups defaultPolicyGroup="mixed_policy_group">
+        <policyGroup id="basic_policy_group">
+            <defaultPolicy state="WaitForVHAL" id="policy_id_other_on"/>
+            <defaultPolicy state="On" id="policy_id_other_untouched"/>
+        </policyGroup>
+        <policyGroup id="no_default_policy_group">
+            <noDefaultPolicy state="WaitForVHAL"/>
+            <noDefaultPolicy state="On"/>
+        </policyGroup>
+        <policyGroup id="mixed_policy_group">
+            <defaultPolicy state="WaitForVHAL" id="policy_id_other_on"/>
+            <noDefaultPolicy state="On"/>
+        </policyGroup>
+    </policyGroups>
+
+    <policies>
+        <policy id="expected_to_be_registered">
+            <otherComponents behavior="on"/>
+        </policy>
+        <policy id="policy_id_other_off">
+            <otherComponents behavior="off"/>
+            <component id="POWER_COMPONENT_AUDIO">off</component>
+            <component id="POWER_COMPONENT_DISPLAY">off</component>
+            <component id="POWER_COMPONENT_WIFI">on</component>
+            <component id="POWER_COMPONENT_VISUAL_INTERACTION">off</component>
+            <component id="POWER_COMPONENT_TRUSTED_DEVICE_DETECTION">off</component>
+        </policy>
+        <policy id="policy_id_other_untouched">
+            <otherComponents behavior="untouched"/>
+            <component id="POWER_COMPONENT_AUDIO">on</component>
+            <component id="POWER_COMPONENT_DISPLAY">on</component>
+            <component id="POWER_COMPONENT_BLUETOOTH">on</component>
+            <component id="POWER_COMPONENT_WIFI">on</component>
+            <component id="POWER_COMPONENT_VOICE_INTERACTION">on</component>
+            <component id="POWER_COMPONENT_VISUAL_INTERACTION">on</component>
+            <component id="POWER_COMPONENT_TRUSTED_DEVICE_DETECTION">on</component>
+        </policy>
+        <policy id="policy_id_other_on">
+            <otherComponents behavior="on"/>
+            <component id="POWER_COMPONENT_AUDIO">off</component>
+            <component id="POWER_COMPONENT_VOICE_INTERACTION">off</component>
+            <component id="POWER_COMPONENT_VISUAL_INTERACTION">off</component>
+            <component id="POWER_COMPONENT_TRUSTED_DEVICE_DETECTION">off</component>
+        </policy>
+        <policy id="policy_id_other_none">
+            <component id="POWER_COMPONENT_AUDIO">off</component>
+            <component id="POWER_COMPONENT_WIFI">on</component>
+            <component id="POWER_COMPONENT_VOICE_INTERACTION">off</component>
+            <component id="POWER_COMPONENT_VISUAL_INTERACTION">off</component>
+            <component id="POWER_COMPONENT_TRUSTED_DEVICE_DETECTION">off</component>
+        </policy>
+    </policies>
+
+    <systemPolicyOverrides>
+        <policy id="system_power_policy_no_user_interaction">
+            <component id="POWER_COMPONENT_BLUETOOTH">on</component>
+            <component id="POWER_COMPONENT_NFC">on</component>
+            <component id="POWER_COMPONENT_TRUSTED_DEVICE_DETECTION">off</component>
+        </policy>
+    </systemPolicyOverrides>
+
+</powerPolicy>
diff --git a/tests/carservice_unit_test/src/com/android/car/power/PolicyReaderUnitTest.java b/tests/carservice_unit_test/src/com/android/car/power/PolicyReaderUnitTest.java
index 1a4a9a4..f3b23cc 100644
--- a/tests/carservice_unit_test/src/com/android/car/power/PolicyReaderUnitTest.java
+++ b/tests/carservice_unit_test/src/com/android/car/power/PolicyReaderUnitTest.java
@@ -210,6 +210,21 @@
     }
 
     @Test
+    public void testValidXmlWithDefaultPolicyGroup() throws Exception {
+        try (InputStream inputStream = mResources.openRawResource(
+                R.raw.valid_power_policy_default_policy_group)) {
+            mPolicyReader.readPowerPolicyFromXml(inputStream);
+        }
+
+        assertThat(mPolicyReader.getDefaultPowerPolicyGroup()).isEqualTo("mixed_policy_group");
+    }
+
+    @Test
+    public void testInvalidXml_wrongDefaultPolicyGroupId() throws Exception {
+        assertInvalidXml(R.raw.invalid_system_power_policy_incorrect_default_power_policy_group_id);
+    }
+
+    @Test
     public void testDefaultPolicies() throws Exception {
         assertDefaultPolicies();
     }