• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2017 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.phone.testapps.embmsmw;
18 
19 import android.app.Service;
20 import android.content.Intent;
21 import android.net.Uri;
22 import android.os.Binder;
23 import android.os.Handler;
24 import android.os.HandlerThread;
25 import android.os.IBinder;
26 import android.telephony.mbms.MbmsErrors;
27 import android.telephony.mbms.MbmsStreamingSessionCallback;
28 import android.telephony.mbms.StreamingService;
29 import android.telephony.mbms.StreamingServiceCallback;
30 import android.telephony.mbms.StreamingServiceInfo;
31 import android.telephony.mbms.vendor.MbmsStreamingServiceBase;
32 import android.util.Log;
33 
34 import com.android.internal.os.SomeArgs;
35 
36 import java.util.Arrays;
37 import java.util.HashMap;
38 import java.util.List;
39 import java.util.Map;
40 import java.util.Set;
41 
42 public class EmbmsTestStreamingService extends Service {
43     private static final Set<String> ALLOWED_PACKAGES = Set.of(
44             "com.android.phone.testapps.embmsfrontend");
45 
46     private static final String TAG = "EmbmsTestStreaming";
47 
48     private static final long INITIALIZATION_DELAY = 200;
49     private static final long SEND_SERVICE_LIST_DELAY = 300;
50     private static final long START_STREAMING_DELAY = 500;
51 
52     private static final int SEND_STREAMING_SERVICES_LIST = 1;
53 
54     private final Map<FrontendAppIdentifier, MbmsStreamingSessionCallback> mAppCallbacks =
55             new HashMap<>();
56 
57     private HandlerThread mHandlerThread;
58     private Handler mHandler;
59     private Handler.Callback mWorkerCallback = (msg) -> {
60         switch (msg.what) {
61             case SEND_STREAMING_SERVICES_LIST:
62                 SomeArgs args = (SomeArgs) msg.obj;
63                 FrontendAppIdentifier appKey = (FrontendAppIdentifier) args.arg1;
64                 List<StreamingServiceInfo> services = (List) args.arg2;
65                 MbmsStreamingSessionCallback appCallback = mAppCallbacks.get(appKey);
66                 if (appCallback != null) {
67                     appCallback.onStreamingServicesUpdated(services);
68                 }
69                 break;
70         }
71         return true;
72     };
73 
74     private final MbmsStreamingServiceBase mBinder = new MbmsStreamingServiceBase() {
75         @Override
76         public int initialize(MbmsStreamingSessionCallback callback, int subId) {
77             int packageUid = Binder.getCallingUid();
78             String[] packageNames = getPackageManager().getPackagesForUid(packageUid);
79             if (packageNames == null) {
80                 return MbmsErrors.InitializationErrors.ERROR_APP_PERMISSIONS_NOT_GRANTED;
81             }
82             boolean isUidAllowed = Arrays.stream(packageNames).anyMatch(ALLOWED_PACKAGES::contains);
83             if (!isUidAllowed) {
84                 return MbmsErrors.InitializationErrors.ERROR_APP_PERMISSIONS_NOT_GRANTED;
85             }
86 
87             mHandler.postDelayed(() -> {
88                 FrontendAppIdentifier appKey = new FrontendAppIdentifier(packageUid, subId);
89                 if (!mAppCallbacks.containsKey(appKey)) {
90                     mAppCallbacks.put(appKey, callback);
91                 } else {
92                     callback.onError(
93                             MbmsErrors.InitializationErrors.ERROR_DUPLICATE_INITIALIZE, "");
94                     return;
95                 }
96                 callback.onMiddlewareReady();
97             }, INITIALIZATION_DELAY);
98             return MbmsErrors.SUCCESS;
99         }
100 
101         @Override
102         public int requestUpdateStreamingServices(int subscriptionId, List<String> serviceClasses) {
103             FrontendAppIdentifier appKey =
104                     new FrontendAppIdentifier(Binder.getCallingUid(), subscriptionId);
105             checkInitialized(appKey);
106 
107             List<StreamingServiceInfo> serviceInfos =
108                     StreamingServiceRepository.getStreamingServicesForClasses(serviceClasses);
109 
110             SomeArgs args = SomeArgs.obtain();
111             args.arg1 = appKey;
112             args.arg2 = serviceInfos;
113 
114             mHandler.removeMessages(SEND_STREAMING_SERVICES_LIST);
115             mHandler.sendMessageDelayed(
116                     mHandler.obtainMessage(SEND_STREAMING_SERVICES_LIST, args),
117                     SEND_SERVICE_LIST_DELAY);
118             return MbmsErrors.SUCCESS;
119         }
120 
121         @Override
122         public int startStreaming(int subscriptionId, String serviceId,
123                 StreamingServiceCallback callback) {
124             FrontendAppIdentifier appKey =
125                     new FrontendAppIdentifier(Binder.getCallingUid(), subscriptionId);
126             checkInitialized(appKey);
127             checkServiceExists(serviceId);
128 
129             if (StreamStateTracker.getStreamingState(appKey, serviceId) ==
130                     StreamingService.STATE_STARTED) {
131                 return MbmsErrors.StreamingErrors.ERROR_DUPLICATE_START_STREAM;
132             }
133 
134             mHandler.postDelayed(
135                     () -> StreamStateTracker.startStreaming(appKey, serviceId, callback,
136                             StreamingService.REASON_BY_USER_REQUEST),
137                     START_STREAMING_DELAY);
138             return MbmsErrors.SUCCESS;
139         }
140 
141         @Override
142         public Uri getPlaybackUri(int subscriptionId, String serviceId) {
143             FrontendAppIdentifier appKey =
144                     new FrontendAppIdentifier(Binder.getCallingUid(), subscriptionId);
145             checkInitialized(appKey);
146             checkServiceExists(serviceId);
147 
148             Uri streamingUri = StreamingServiceRepository.getUriForService(serviceId);
149             if (streamingUri == null) {
150                 throw new IllegalArgumentException("Invalid service ID");
151             }
152             return streamingUri;
153         }
154 
155         @Override
156         public void stopStreaming(int subscriptionId, String serviceId) {
157             FrontendAppIdentifier appKey =
158                     new FrontendAppIdentifier(Binder.getCallingUid(), subscriptionId);
159             checkInitialized(appKey);
160             checkServiceExists(serviceId);
161 
162             mHandler.post(() -> StreamStateTracker.stopStreaming(appKey, serviceId,
163                     StreamingService.REASON_BY_USER_REQUEST));
164             StreamStateTracker.dispose(appKey, serviceId);
165         }
166 
167         @Override
168         public void dispose(int subscriptionId) {
169             FrontendAppIdentifier appKey =
170                     new FrontendAppIdentifier(Binder.getCallingUid(), subscriptionId);
171             checkInitialized(appKey);
172 
173             Log.i(TAG, "Disposing app with uid " + Binder.getCallingUid());
174             StreamStateTracker.disposeAll(appKey);
175             mAppCallbacks.remove(appKey);
176         }
177 
178         @Override
179         public void onAppCallbackDied(int uid, int subscriptionId) {
180             FrontendAppIdentifier appKey = new FrontendAppIdentifier(uid, subscriptionId);
181 
182             Log.i(TAG, "Disposing app " + appKey + " due to binder death");
183             StreamStateTracker.disposeAll(appKey);
184             mAppCallbacks.remove(appKey);
185         }
186     };
187 
188     @Override
onDestroy()189     public void onDestroy() {
190         super.onCreate();
191         mHandlerThread.quitSafely();
192         logd("EmbmsTestStreamingService onDestroy");
193     }
194 
195     @Override
onBind(Intent intent)196     public IBinder onBind(Intent intent) {
197         logd("EmbmsTestStreamingService onBind");
198         mHandlerThread = new HandlerThread("EmbmsTestStreamingServiceWorker");
199         mHandlerThread.start();
200         mHandler = new Handler(mHandlerThread.getLooper(), mWorkerCallback);
201         return mBinder;
202     }
203 
logd(String s)204     private static void logd(String s) {
205         Log.d(TAG, s);
206     }
207 
checkInitialized(FrontendAppIdentifier appKey)208     private void checkInitialized(FrontendAppIdentifier appKey) {
209         if (!mAppCallbacks.containsKey(appKey)) {
210             throw new IllegalStateException("Not yet initialized");
211         }
212     }
213 
checkServiceExists(String serviceId)214     private void checkServiceExists(String serviceId) {
215         if (StreamingServiceRepository.getStreamingServiceInfoForId(serviceId) == null) {
216             throw new IllegalArgumentException("Invalid service ID");
217         }
218     }
219 }
220