• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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;
18 
19 import static android.telephony.TelephonyManager.SIM_STATE_LOADED;
20 
21 import static com.android.imsserviceentitlement.entitlement.EntitlementConfiguration.ClientBehavior.NEEDS_TO_RESET;
22 import static com.android.imsserviceentitlement.entitlement.EntitlementConfiguration.ClientBehavior.VALID_DURING_VALIDITY;
23 import static com.android.imsserviceentitlement.entitlement.EntitlementConfiguration.ClientBehavior.VALID_WITHOUT_DURATION;
24 import static com.android.imsserviceentitlement.ts43.Ts43Constants.EntitlementVersion.ENTITLEMENT_VERSION_EIGHT;
25 import static com.android.imsserviceentitlement.ts43.Ts43Constants.EntitlementVersion.ENTITLEMENT_VERSION_TWO;
26 import static com.android.imsserviceentitlement.utils.Executors.getAsyncExecutor;
27 
28 import android.content.BroadcastReceiver;
29 import android.content.Context;
30 import android.content.Intent;
31 import android.content.SharedPreferences;
32 import android.os.UserManager;
33 import android.provider.Settings;
34 import android.telephony.CarrierConfigManager;
35 import android.telephony.SubscriptionManager;
36 import android.util.Log;
37 
38 import androidx.annotation.VisibleForTesting;
39 import androidx.annotation.WorkerThread;
40 
41 import com.android.imsserviceentitlement.entitlement.EntitlementConfiguration;
42 import com.android.imsserviceentitlement.entitlement.EntitlementConfiguration.ClientBehavior;
43 import com.android.imsserviceentitlement.job.JobManager;
44 import com.android.imsserviceentitlement.utils.TelephonyUtils;
45 
46 /** Watches events and manages service entitlement polling. */
47 public class ImsEntitlementReceiver extends BroadcastReceiver {
48     private static final String TAG = "IMSSE-ImsEntitlementReceiver";
49 
50     /**
51      * Shared preference name for activation information, the key used in this file should append
52      * slot id if the value depended on carrier.
53      */
54     private static final String PREFERENCE_ACTIVATION_INFO = "PREFERENCE_ACTIVATION_INFO";
55     /**
56      * Shared preference key for last known subscription id of a SIM slot; default value {@link
57      * SubscriptionManager#INVALID_SUBSCRIPTION_ID}.
58      */
59     private static final String KEY_LAST_SUB_ID = "last_sub_id_";
60     /** Shared preference key for last boot count. */
61     private static final String KEY_LAST_BOOT_COUNT = "last_boot_count_";
62 
63     @Override
onReceive(Context context, Intent intent)64     public void onReceive(Context context, Intent intent) {
65         int currentSubId =
66                 intent.getIntExtra(
67                         SubscriptionManager.EXTRA_SUBSCRIPTION_INDEX,
68                         SubscriptionManager.INVALID_SUBSCRIPTION_ID);
69         int slotId =
70                 intent.getIntExtra(
71                         SubscriptionManager.EXTRA_SLOT_INDEX,
72                         SubscriptionManager.INVALID_SIM_SLOT_INDEX);
73         Dependencies dependencies = createDependency(context, currentSubId);
74         if (!dependencies.userManager.isSystemUser()
75                 || !SubscriptionManager.isValidSubscriptionId(currentSubId)
76                 || dependencies.telephonyUtils.getSimApplicationState() != SIM_STATE_LOADED
77                 || !TelephonyUtils.isImsProvisioningRequired(context, currentSubId)
78                 || !isEntitlementVersionSupported(context, currentSubId)) {
79             return;
80         }
81 
82         String action = intent.getAction();
83         if (CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED.equals(action)) {
84             final PendingResult result = goAsync();
85             getAsyncExecutor().execute(
86                     () -> handleCarrierConfigChanged(
87                             context, currentSubId, slotId, dependencies.jobManager, result));
88         }
89     }
90 
91     /**
92      * Handles the event of SIM change and device boot up while receiving {@link
93      * CarrierConfigManager#ACTION_CARRIER_CONFIG_CHANGED}.
94      */
95     @WorkerThread
handleCarrierConfigChanged( Context context, int currentSubId, int slotId, JobManager jobManager, PendingResult result)96     private void handleCarrierConfigChanged(
97             Context context, int currentSubId, int slotId, JobManager jobManager,
98             PendingResult result) {
99         boolean shouldQuery = false;
100 
101         // Handle SIM changed.
102         int lastSubId = getAndSetSubId(context, currentSubId, slotId);
103         if (currentSubId != lastSubId) {
104             Log.d(TAG,
105                     "SubId for slot " + slotId + " changed: " + lastSubId + " -> " + currentSubId);
106             if (SubscriptionManager.isValidSubscriptionId(lastSubId)) {
107                 new EntitlementConfiguration(context, lastSubId).reset();
108             }
109             shouldQuery = true;
110         }
111 
112         // Handle device boot up.
113         if (!shouldQuery && isBootUp(context, slotId)) {
114             EntitlementConfiguration entitlementConfiguration =
115                     new EntitlementConfiguration(context, currentSubId);
116             ClientBehavior clientBehavior = entitlementConfiguration.entitlementValidation();
117             Log.d(TAG, "Device boot up, clientBehavior = " + clientBehavior);
118             if (clientBehavior == VALID_DURING_VALIDITY
119                     || clientBehavior == VALID_WITHOUT_DURATION
120                     || clientBehavior == NEEDS_TO_RESET) {
121                 shouldQuery = true;
122             } else { // NEEDS_TO_RESET_EXCEPT_VERS or NEEDS_TO_RESET_EXCEPT_VERS_UNTIL_SETTING_ON
123                 int storedEntitlementVersion = entitlementConfiguration.getEntitlementVersion();
124                 int entitlementVersion =
125                         TelephonyUtils.getEntitlementVersion(context, currentSubId);
126                 if (storedEntitlementVersion != entitlementVersion && entitlementVersion >= 8) {
127                     shouldQuery = true;
128                 }
129             }
130         }
131 
132         if (shouldQuery) {
133             jobManager.queryEntitlementStatusOnceNetworkReady();
134         }
135 
136         if (result != null) {
137             result.finish();
138         }
139     }
140 
141     /**
142      * Returns {@code true} if current boot count greater than previous one. Saves the latest boot
143      * count into shared preference.
144      */
145     @VisibleForTesting
isBootUp(Context context, int slotId)146     boolean isBootUp(Context context, int slotId) {
147         SharedPreferences preferences =
148                 context.getSharedPreferences(PREFERENCE_ACTIVATION_INFO, Context.MODE_PRIVATE);
149         int lastBootCount = preferences.getInt(KEY_LAST_BOOT_COUNT + slotId, 0);
150         int currentBootCount =
151                 Settings.Global.getInt(
152                         context.getContentResolver(), Settings.Global.BOOT_COUNT, /* def= */ -1);
153         preferences.edit().putInt(KEY_LAST_BOOT_COUNT + slotId, currentBootCount).apply();
154 
155         return currentBootCount != lastBootCount;
156     }
157 
getAndSetSubId(Context context, int currentSubId, int slotId)158     private int getAndSetSubId(Context context, int currentSubId, int slotId) {
159         SharedPreferences preferences =
160                 context.getSharedPreferences(PREFERENCE_ACTIVATION_INFO, Context.MODE_PRIVATE);
161         int lastSubId = preferences.getInt(
162                 KEY_LAST_SUB_ID + slotId, SubscriptionManager.INVALID_SUBSCRIPTION_ID);
163         preferences.edit().putInt(KEY_LAST_SUB_ID + slotId, currentSubId).apply();
164         return lastSubId;
165     }
166 
isEntitlementVersionSupported(Context context, int currentSubId)167     private boolean isEntitlementVersionSupported(Context context, int currentSubId) {
168         int entitlementVersion = TelephonyUtils.getEntitlementVersion(context, currentSubId);
169         if (entitlementVersion == ENTITLEMENT_VERSION_TWO
170                 || entitlementVersion == ENTITLEMENT_VERSION_EIGHT) {
171             return true;
172         }
173         Log.d(TAG, "Unsupported entitltment version: " + entitlementVersion);
174         return false;
175     }
176 
177     /** Returns initialized dependencies */
178     @VisibleForTesting
createDependency(Context context, int subId)179     Dependencies createDependency(Context context, int subId) {
180         // Wrap return value
181         Dependencies ret = new Dependencies();
182         ret.telephonyUtils = new TelephonyUtils(context, subId);
183         ret.userManager = context.getSystemService(UserManager.class);
184         ret.jobManager =
185                 JobManager.getInstance(context, ImsEntitlementPollingService.COMPONENT_NAME, subId);
186         return ret;
187     }
188 
189     /** A collection of dependency objects */
190     protected static class Dependencies {
191         public TelephonyUtils telephonyUtils;
192         public UserManager userManager;
193         public JobManager jobManager;
194     }
195 }
196