• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2019 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.server.wifi;
18 
19 import android.annotation.NonNull;
20 import android.content.Context;
21 import android.content.ContextWrapper;
22 import android.content.Intent;
23 import android.content.pm.PackageManager;
24 import android.content.pm.ResolveInfo;
25 import android.content.res.AssetManager;
26 import android.content.res.Resources;
27 import android.util.Log;
28 
29 import com.android.server.wifi.util.Environment;
30 
31 import java.util.List;
32 import java.util.stream.Collectors;
33 
34 /**
35  * Wrapper for context to override getResources method. Resources for wifi mainline jar needs to be
36  * fetched from the resources APK.
37  */
38 public class WifiContext extends ContextWrapper {
39     private static final String TAG = "WifiContext";
40     /** Intent action that is used to identify ServiceWifiResources.apk */
41     private static final String ACTION_RESOURCES_APK =
42             "com.android.server.wifi.intent.action.SERVICE_WIFI_RESOURCES_APK";
43 
44     /** Since service-wifi runs within system_server, its package name is "android". */
45     private static final String SERVICE_WIFI_PACKAGE_NAME = "android";
46 
47     private String mWifiOverlayApkPkgName;
48 
49     // Cached resources from the resources APK.
50     private AssetManager mWifiAssetsFromApk;
51     private Resources mWifiResourcesFromApk;
52     private Resources.Theme mWifiThemeFromApk;
53 
WifiContext(@onNull Context contextBase)54     public WifiContext(@NonNull Context contextBase) {
55         super(contextBase);
56     }
57 
58     /** Get the package name of ServiceWifiResources.apk */
getWifiOverlayApkPkgName()59     public String getWifiOverlayApkPkgName() {
60         if (mWifiOverlayApkPkgName != null) {
61             return mWifiOverlayApkPkgName;
62         }
63 
64         List<ResolveInfo> resolveInfos = getPackageManager().queryIntentActivities(
65                 new Intent(ACTION_RESOURCES_APK),
66                 PackageManager.MATCH_SYSTEM_ONLY);
67 
68         // remove apps that don't live in the Wifi apex
69         resolveInfos.removeIf(info ->
70                 !Environment.isAppInWifiApex(info.activityInfo.applicationInfo));
71 
72         if (resolveInfos.isEmpty()) {
73             // Resource APK not loaded yet, print a stack trace to see where this is called from
74             Log.e(TAG, "Attempted to fetch resources before Wifi Resources APK is loaded!",
75                     new IllegalStateException());
76             return null;
77         }
78 
79         if (resolveInfos.size() > 1) {
80             // multiple apps found, log a warning, but continue
81             Log.w(TAG, "Found > 1 APK that can resolve Wifi Resources APK intent: "
82                     + resolveInfos.stream()
83                             .map(info -> info.activityInfo.applicationInfo.packageName)
84                             .collect(Collectors.joining(", ")));
85         }
86 
87         // Assume the first ResolveInfo is the one we're looking for
88         ResolveInfo info = resolveInfos.get(0);
89         mWifiOverlayApkPkgName = info.activityInfo.applicationInfo.packageName;
90         Log.i(TAG, "Found Wifi Resources APK at: " + mWifiOverlayApkPkgName);
91         return mWifiOverlayApkPkgName;
92     }
93 
getResourcesApkContext()94     private Context getResourcesApkContext() {
95         try {
96             return createPackageContext(getWifiOverlayApkPkgName(), 0);
97         } catch (PackageManager.NameNotFoundException e) {
98             Log.wtf(TAG, "Failed to load resources", e);
99         }
100         return null;
101     }
102 
103     /**
104      * Retrieve assets held in the wifi resources APK.
105      */
106     @Override
getAssets()107     public AssetManager getAssets() {
108         if (mWifiAssetsFromApk == null) {
109             Context resourcesApkContext = getResourcesApkContext();
110             if (resourcesApkContext != null) {
111                 mWifiAssetsFromApk = resourcesApkContext.getAssets();
112             }
113         }
114         return mWifiAssetsFromApk;
115     }
116 
117     /**
118      * Retrieve resources held in the wifi resources APK.
119      */
120     @Override
getResources()121     public Resources getResources() {
122         if (mWifiResourcesFromApk == null) {
123             Context resourcesApkContext = getResourcesApkContext();
124             if (resourcesApkContext != null) {
125                 mWifiResourcesFromApk = resourcesApkContext.getResources();
126             }
127         }
128         return mWifiResourcesFromApk;
129     }
130 
131     /**
132      * Retrieve theme held in the wifi resources APK.
133      */
134     @Override
getTheme()135     public Resources.Theme getTheme() {
136         if (mWifiThemeFromApk == null) {
137             Context resourcesApkContext = getResourcesApkContext();
138             if (resourcesApkContext != null) {
139                 mWifiThemeFromApk = resourcesApkContext.getTheme();
140             }
141         }
142         return mWifiThemeFromApk;
143     }
144 
145     /** Get the package name that service-wifi runs under. */
getServiceWifiPackageName()146     public String getServiceWifiPackageName() {
147         return SERVICE_WIFI_PACKAGE_NAME;
148     }
149 }
150