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 android.telephony.mbms;
18 
19 import android.content.ComponentName;
20 import android.content.Context;
21 import android.content.Intent;
22 import android.content.ServiceConnection;
23 import android.content.pm.*;
24 import android.content.pm.ServiceInfo;
25 import android.telephony.MbmsDownloadSession;
26 import android.telephony.MbmsGroupCallSession;
27 import android.telephony.MbmsStreamingSession;
28 import android.util.Log;
29 
30 import java.io.File;
31 import java.io.IOException;
32 import java.util.List;
33 
34 /**
35  * @hide
36  */
37 public class MbmsUtils {
38     private static final String LOG_TAG = "MbmsUtils";
39 
isContainedIn(File parent, File child)40     public static boolean isContainedIn(File parent, File child) {
41         try {
42             String parentPath = parent.getCanonicalPath();
43             String childPath = child.getCanonicalPath();
44             return childPath.startsWith(parentPath);
45         } catch (IOException e) {
46             throw new RuntimeException("Failed to resolve canonical paths: " + e);
47         }
48     }
49 
toComponentName(ComponentInfo ci)50     public static ComponentName toComponentName(ComponentInfo ci) {
51         return new ComponentName(ci.packageName, ci.name);
52     }
53 
getOverrideServiceName(Context context, String serviceAction)54     public static ComponentName getOverrideServiceName(Context context, String serviceAction) {
55         String metaDataKey = null;
56         switch (serviceAction) {
57             case MbmsDownloadSession.MBMS_DOWNLOAD_SERVICE_ACTION:
58                 metaDataKey = MbmsDownloadSession.MBMS_DOWNLOAD_SERVICE_OVERRIDE_METADATA;
59                 break;
60             case MbmsStreamingSession.MBMS_STREAMING_SERVICE_ACTION:
61                 metaDataKey = MbmsStreamingSession.MBMS_STREAMING_SERVICE_OVERRIDE_METADATA;
62                 break;
63             case MbmsGroupCallSession.MBMS_GROUP_CALL_SERVICE_ACTION:
64                 metaDataKey = MbmsGroupCallSession.MBMS_GROUP_CALL_SERVICE_OVERRIDE_METADATA;
65                 break;
66         }
67         if (metaDataKey == null) {
68             return null;
69         }
70 
71         ApplicationInfo appInfo;
72         try {
73             appInfo = context.getPackageManager()
74                     .getApplicationInfo(context.getPackageName(), PackageManager.GET_META_DATA);
75         } catch (PackageManager.NameNotFoundException e) {
76             return null;
77         }
78         if (appInfo.metaData == null) {
79             return null;
80         }
81         String serviceComponent = appInfo.metaData.getString(metaDataKey);
82         if (serviceComponent == null) {
83             return null;
84         }
85         return ComponentName.unflattenFromString(serviceComponent);
86     }
87 
getMiddlewareServiceInfo(Context context, String serviceAction)88     public static ServiceInfo getMiddlewareServiceInfo(Context context, String serviceAction) {
89         // Query for the proper service
90         PackageManager packageManager = context.getPackageManager();
91         Intent queryIntent = new Intent();
92         queryIntent.setAction(serviceAction);
93 
94         ComponentName overrideService = getOverrideServiceName(context, serviceAction);
95         List<ResolveInfo> services;
96         if (overrideService == null) {
97             services = packageManager.queryIntentServices(queryIntent,
98                     PackageManager.MATCH_SYSTEM_ONLY);
99         } else {
100             queryIntent.setComponent(overrideService);
101             services = packageManager.queryIntentServices(queryIntent,
102                     PackageManager.MATCH_ALL);
103         }
104 
105         if (services == null || services.size() == 0) {
106             Log.w(LOG_TAG, "No MBMS services found, cannot get service info");
107             return null;
108         }
109 
110         if (services.size() > 1) {
111             Log.w(LOG_TAG, "More than one MBMS service found, cannot get unique service");
112             return null;
113         }
114         return services.get(0).serviceInfo;
115     }
116 
startBinding(Context context, String serviceAction, ServiceConnection serviceConnection)117     public static int startBinding(Context context, String serviceAction,
118             ServiceConnection serviceConnection) {
119         Intent bindIntent = new Intent();
120         ServiceInfo mbmsServiceInfo =
121                 MbmsUtils.getMiddlewareServiceInfo(context, serviceAction);
122 
123         if (mbmsServiceInfo == null) {
124             return MbmsErrors.ERROR_NO_UNIQUE_MIDDLEWARE;
125         }
126 
127         bindIntent.setComponent(MbmsUtils.toComponentName(mbmsServiceInfo));
128 
129         context.bindService(bindIntent, serviceConnection, Context.BIND_AUTO_CREATE);
130         return MbmsErrors.SUCCESS;
131     }
132 
133     /**
134      * Returns a File linked to the directory used to store temp files for this file service
135      */
getEmbmsTempFileDirForService(Context context, String serviceId)136     public static File getEmbmsTempFileDirForService(Context context, String serviceId) {
137         // Replace all non-alphanumerics/underscores with an underscore. Some filesystems don't
138         // like special characters.
139         String sanitizedServiceId = serviceId.replaceAll("[^a-zA-Z0-9_]", "_");
140 
141         File embmsTempFileDir = MbmsTempFileProvider.getEmbmsTempFileDir(context);
142 
143         return new File(embmsTempFileDir, sanitizedServiceId);
144     }
145 }
146