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