• 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.fcm;
18 
19 import android.app.job.JobParameters;
20 import android.app.job.JobService;
21 import android.content.ComponentName;
22 import android.content.Context;
23 import android.os.AsyncTask;
24 import android.telephony.SubscriptionManager;
25 import android.util.Log;
26 
27 import androidx.annotation.VisibleForTesting;
28 
29 import com.android.imsserviceentitlement.R;
30 import com.android.imsserviceentitlement.job.JobManager;
31 import com.android.imsserviceentitlement.utils.TelephonyUtils;
32 
33 import com.google.firebase.FirebaseApp;
34 import com.google.firebase.FirebaseOptions;
35 import com.google.firebase.iid.FirebaseInstanceId;
36 import com.google.firebase.messaging.FirebaseMessaging;
37 
38 import java.io.IOException;
39 
40 /** A {@link JobService} that gets a FCM tokens for all active SIMs. */
41 public class FcmRegistrationService extends JobService {
42     private static final String TAG = "IMSSE-FcmRegistrationService";
43 
44     private FirebaseInstanceId mFakeInstanceID = null;
45     private FirebaseApp mApp = null;
46 
47     @VisibleForTesting AsyncTask<JobParameters, Void, Void> mOngoingTask;
48 
49     /** Enqueues a job for FCM registration. */
enqueueJob(Context context)50     public static void enqueueJob(Context context) {
51         ComponentName componentName = new ComponentName(context, FcmRegistrationService.class);
52         // No subscription id associated job, use {@link
53         // SubscriptionManager#INVALID_SUBSCRIPTION_ID}.
54         JobManager jobManager =
55                 JobManager.getInstance(
56                         context, componentName, SubscriptionManager.INVALID_SUBSCRIPTION_ID);
57         jobManager.registerFcmOnceNetworkReady();
58     }
59 
60     @VisibleForTesting
setFakeInstanceID(FirebaseInstanceId instanceID)61     void setFakeInstanceID(FirebaseInstanceId instanceID) {
62         mFakeInstanceID = instanceID;
63     }
64 
65     @Override
66     @VisibleForTesting
attachBaseContext(Context base)67     protected void attachBaseContext(Context base) {
68         super.attachBaseContext(base);
69     }
70 
71     @Override
onCreate()72     public void onCreate() {
73         super.onCreate();
74         try {
75             mApp = FirebaseApp.getInstance();
76         } catch (IllegalStateException e) {
77             Log.d(TAG, "initialize FirebaseApp");
78             mApp = FirebaseApp.initializeApp(
79                     this,
80                     new FirebaseOptions.Builder()
81                             .setApplicationId(getResources().getString(R.string.fcm_app_id))
82                             .setProjectId(getResources().getString(R.string.fcm_project_id))
83                             .setApiKey(getResources().getString(R.string.fcm_api_key))
84                             .build());
85         }
86     }
87 
88     @Override
onStartJob(JobParameters params)89     public boolean onStartJob(JobParameters params) {
90         mOngoingTask = new AsyncTask<JobParameters, Void, Void>() {
91             @Override
92             protected Void doInBackground(JobParameters... params) {
93                 onHandleWork(params[0]);
94                 return null;
95             }
96         };
97         mOngoingTask.execute(params);
98         return true;
99     }
100 
101     @Override
onStopJob(JobParameters params)102     public boolean onStopJob(JobParameters params) {
103         return true; // Always re-run if job stopped.
104     }
105 
106     /**
107      * Registers to receive FCM messages published to subscribe topics under the retrieved token.
108      * The token changes when the InstanceID becomes invalid (e.g. app data is deleted).
109      */
onHandleWork(JobParameters params)110     protected void onHandleWork(JobParameters params) {
111         boolean wantsReschedule = false;
112         FirebaseInstanceId instanceID = getFirebaseInstanceId();
113         if (instanceID == null) {
114             Log.d(TAG, "Cannot get fcm token because FirebaseInstanceId is null");
115             return;
116         }
117         for (int subId : TelephonyUtils.getSubIdsWithFcmSupported(this)) {
118             if (!updateFcmToken(instanceID, subId)) {
119                 wantsReschedule = true;
120             }
121         }
122 
123         jobFinished(params, wantsReschedule);
124     }
125 
126     /** Returns {@code false} if failed to get token. */
updateFcmToken(FirebaseInstanceId instanceID, int subId)127     private boolean updateFcmToken(FirebaseInstanceId instanceID, int subId) {
128         Log.d(TAG, "FcmRegistrationService.updateFcmToken: subId=" + subId);
129         String token = getTokenForSubId(instanceID, subId);
130         if (token == null) {
131             Log.d(TAG, "getToken null");
132             return false;
133         }
134         Log.d(TAG, "FCM token: " + token + " subId: " + subId);
135         FcmTokenStore.setToken(this, subId, token);
136         return true;
137     }
138 
getFirebaseInstanceId()139     private FirebaseInstanceId getFirebaseInstanceId() {
140         return (mFakeInstanceID != null) ? mFakeInstanceID : FirebaseInstanceId.getInstance(mApp);
141     }
142 
getTokenForSubId(FirebaseInstanceId instanceID, int subId)143     private String getTokenForSubId(FirebaseInstanceId instanceID, int subId) {
144         String token = null;
145         try {
146             token = instanceID.getToken(
147                     TelephonyUtils.getFcmSenderId(this, subId),
148                     FirebaseMessaging.INSTANCE_ID_SCOPE);
149         } catch (IOException e) {
150             Log.e(TAG, "Failed to get a new FCM token: " + e);
151         }
152         return token;
153     }
154 }
155