1 /*
2  * Copyright (C) 2021 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 package com.android.imsserviceentitlement.entitlement;
18 
19 import android.content.Context;
20 
21 import androidx.annotation.VisibleForTesting;
22 
23 import com.android.imsserviceentitlement.ts43.Ts43Constants.ResponseXmlAttributes;
24 import com.android.imsserviceentitlement.ts43.Ts43Constants.ResponseXmlNode;
25 import com.android.imsserviceentitlement.utils.XmlDoc;
26 import com.android.libraries.entitlement.ServiceEntitlement;
27 
28 import java.util.Optional;
29 import java.util.concurrent.TimeUnit;
30 
31 /** Provides the entitlement characteristic which stored from previous query. */
32 public class EntitlementConfiguration {
33     /** Default value of version for VERS characteristic. */
34     private static final int DEFAULT_VERSION = 0;
35     /** Default value of validity for VERS and TOKEN characteristics. */
36     private static final long DEFAULT_VALIDITY = 0;
37     /** Default value of VoLTE/VoWifi/SMSoverIP entitlemenet status. */
38     private static final int INCOMPATIBLE_STATE = 2;
39     /** Default raw XML with both version and validity set to -1. */
40     @VisibleForTesting
41     public static final String RAW_XML_VERS_MINUS_ONE =
42                                 "<wap-provisioningdoc version=\"1.1\">"
43                                 + "  <characteristic type=\"VERS\">"
44                                 + "    <parm name=\"version\" value=\"-1\"/>"
45                                 + "    <parm name=\"validity\" value=\"-1\"/>"
46                                 + "  </characteristic>"
47                                 + "  <characteristic type=\"TOKEN\">"
48                                 + "    <parm name=\"token\" value=\"\"/>"
49                                 + "    <parm name=\"validity\" value=\"0\"/>"
50                                 + "  </characteristic>"
51                                 + "</wap-provisioningdoc>";
52     /** Default raw XML with both version and validity set to -2. */
53     @VisibleForTesting
54     public static final String RAW_XML_VERS_MINUS_TWO =
55                                 "<wap-provisioningdoc version=\"1.1\">"
56                                 + "  <characteristic type=\"VERS\">"
57                                 + "    <parm name=\"version\" value=\"-2\"/>"
58                                 + "    <parm name=\"validity\" value=\"-2\"/>"
59                                 + "  </characteristic>"
60                                 + "  <characteristic type=\"TOKEN\">"
61                                 + "    <parm name=\"token\" value=\"\"/>"
62                                 + "    <parm name=\"validity\" value=\"0\"/>"
63                                 + "  </characteristic>"
64                                 + "</wap-provisioningdoc>";
65 
66     private final EntitlementConfigurationsDataStore mConfigurationsDataStore;
67     private XmlDoc mXmlDoc;
68 
EntitlementConfiguration(Context context, int subId)69     public EntitlementConfiguration(Context context, int subId) {
70         mConfigurationsDataStore = EntitlementConfigurationsDataStore.getInstance(context, subId);
71         mXmlDoc = new XmlDoc(mConfigurationsDataStore.getRawXml().orElse(null));
72     }
73 
74     // Updates raw XML only.
update(String rawXml)75     private void update(String rawXml) {
76         mConfigurationsDataStore.set(rawXml);
77         mXmlDoc = new XmlDoc(rawXml);
78     }
79 
80     /** Updates entitlement version and raw XML. */
update(int version, String rawXml)81     public void update(int version, String rawXml) {
82         mConfigurationsDataStore.set(version, rawXml);
83         mXmlDoc = new XmlDoc(rawXml);
84     }
85 
86     /** Returns the raw XML stored in the {@link EntitlementConfigurationsDataStore}. */
87     @VisibleForTesting
getRawXml()88     public String getRawXml() {
89         return mConfigurationsDataStore.getRawXml().orElse(null);
90     }
91 
92     /** Returns the entitlement version stored in the {@link EntitlementConfigurationsDataStore}. */
getEntitlementVersion()93     public int getEntitlementVersion() {
94         return  Integer.parseInt(mConfigurationsDataStore.getEntitlementVersion().orElse("0"));
95     }
96 
97     /**
98      * Returns token stored in the {@link EntitlementConfigurationsDataStore} if it is in validity
99      * period. Returns {@link Optional#empty()} if the token was expired or the value of token
100      * validity not positive.
101      */
getToken()102     public Optional<String> getToken() {
103         return isTokenInValidityPeriod()
104                 ? mXmlDoc.getFromToken(ResponseXmlAttributes.TOKEN)
105                 : Optional.empty();
106     }
107 
isTokenInValidityPeriod()108     private boolean isTokenInValidityPeriod() {
109         long queryTimeMillis = mConfigurationsDataStore.getQueryTimeMillis();
110         long tokenValidityMillis = TimeUnit.SECONDS.toMillis(getTokenValidity());
111 
112         if (queryTimeMillis <= 0) {
113             // False if the query time not been set.
114             return false;
115         }
116 
117         // When the token validity is set to 0, the Entitlement Client shall store the token without
118         // any limitation of duration.
119         if (tokenValidityMillis <= 0) {
120             return true;
121         }
122 
123         return (System.currentTimeMillis() - queryTimeMillis) < tokenValidityMillis;
124     }
125 
126     /**
127      * Returns the validity of the token, in seconds. The validity is counted from the time it is
128      * received by the client. If no data exist then returns default value 0.
129      */
getTokenValidity()130     public long getTokenValidity() {
131         return mXmlDoc.getFromToken(ResponseXmlAttributes.VALIDITY)
132                 .map(Long::parseLong)
133                 .orElse(DEFAULT_VALIDITY);
134     }
135 
136     /**
137      * Returns version stored in the {@link EntitlementCharacteristicDataStore}.
138      * If no data exists then return the default value {@link #DEFAULT_VERSION}.
139      */
getVersion()140     public String getVersion() {
141         return mXmlDoc.getFromVersion(ResponseXmlAttributes.VERSION)
142                 .orElse(String.valueOf(DEFAULT_VERSION));
143     }
144 
145     /**
146      * Returns the validity of the version, in seconds. The validity is counted from the time it is
147      * received by the client. If no data exist then returns default value 0.
148      */
getVersValidity()149     public long getVersValidity() {
150         return mXmlDoc.getFromVersion(ResponseXmlAttributes.VALIDITY)
151                 .map(Long::parseLong)
152                 .orElse(DEFAULT_VALIDITY);
153     }
154 
155     public enum ClientBehavior {
156         /** Unknown behavior. */
157         UNKNOWN_BEHAVIOR,
158         /** Entitlement data is valid during validity seconds. */
159         VALID_DURING_VALIDITY,
160         /** Entitlement data is valid without any limitation of duration. */
161         VALID_WITHOUT_DURATION,
162         /** Entitlement data has to be reset to default configuration */
163         NEEDS_TO_RESET,
164         /**
165          * Entitlement data has to be reset to default configuration except for version and
166          * validity. The Entitlement Client shall not perform client configuration requests anymore
167          * for the services just configured.
168          */
169         NEEDS_TO_RESET_EXCEPT_VERS,
170         /**
171          * entitlement data has to be reset to default configuration except for version and
172          * validity. The Entitlement Client shall not perform client configuration requests anymore
173          * for the services just configured, until the end-user switches the setting to On.
174          */
175         NEEDS_TO_RESET_EXCEPT_VERS_UNTIL_SETTING_ON,
176     }
177 
178     /** Returns {@link ClientBehavior} for the service to be configured. */
entitlementValidation()179     public ClientBehavior entitlementValidation() {
180         int version = Integer.parseInt(getVersion());
181         long validity = getVersValidity();
182 
183         if (version > 0 && validity > 0) {
184             return ClientBehavior.VALID_DURING_VALIDITY;
185         } else if (version > 0 && validity == 0) {
186             return ClientBehavior.VALID_WITHOUT_DURATION;
187         } else if (version == 0 && validity == 0) {
188             return ClientBehavior.NEEDS_TO_RESET;
189         } else if (version == -1 && validity == -1) {
190             return ClientBehavior.NEEDS_TO_RESET_EXCEPT_VERS;
191         } else if (version == -2 && validity == -2) {
192             return ClientBehavior.NEEDS_TO_RESET_EXCEPT_VERS_UNTIL_SETTING_ON;
193         }
194 
195         // Should never reach.
196         return ClientBehavior.UNKNOWN_BEHAVIOR;
197     }
198 
199     /**
200      * Removes the stored configuration and reverts to the default configuration when:
201      * <ul>
202      *   <li>on SIM card change
203      *   <li>on menu Factory reset
204      *   <li>reset by the Service Provider (i.e. configuration version set to 0).
205      *       In that case, version and validity are not reset
206      * </ul>
207      */
reset()208     public void reset() {
209         // Default configuration of the Characteristics:
210         //   - VERS.version = 0
211         //   - VERS.validity = 0
212         //   - TOKEN.token = null (i.e. no value assigned)
213         //   - TOKEN.validity =0
214         update(null);
215     }
216 
217     /** Reverts to the default configurations except the version and validity. */
reset(ClientBehavior clientBehavior)218     public void reset(ClientBehavior clientBehavior) {
219         String rawXml = null;
220         if (clientBehavior == ClientBehavior.NEEDS_TO_RESET_EXCEPT_VERS) {
221             rawXml = RAW_XML_VERS_MINUS_ONE;
222         } else if (clientBehavior == ClientBehavior.NEEDS_TO_RESET_EXCEPT_VERS_UNTIL_SETTING_ON) {
223             rawXml = RAW_XML_VERS_MINUS_TWO;
224         }
225         update(rawXml);
226     }
227 }
228