frameworks/base/services/java/com/android/server/SystemServer.java
因为wifiservice在system_server里启动,在这儿监测的时间,总共用了2s,暂时高通基线只用了100多ms, 与高通基线代码无任何修改,所以wifiservice代码本身的代码没问题
最后经各种加日志分析,发现是一个获取wifiContext对象的时候,用了2s
尝试解决办法一:
使用了android 系统的perf来监测system_server的各个线程使用情况,想知道哪个具体的加载函数出的问题,但是貌似没怎么生效
尝试解决办法二:
1、尝试将WifiContext获取的时候使用另一个线程获取,但是后面会遇到各种crash
2、尝试在Wifiservice构造的时候延迟,会发生后续WifiScanService的crash
尝试解决办法三:
1、尝试在system_server一开始的时候获取WifiContext资源,然后在Wifiservice的启动的时候将mContext对象传进WifiService里,结果发现WifiService通过jar包加载,无法传入参数
2、尝试在system_server一开始的时候创建WifiContext资源,将这个资源对象写入一个单例里,然后使用资源对象的时候,阻塞的获取,但是因为创建对象的地方放在了PackageManage
service启动之前,所以出现了各种crash,尤其是在get的时候crash,
3、最后成功的是,基于解决办法三里的2, 创建的时候放在PackageManageService启动之后
首先创建一个WifiHelper.java, 用一个线程获取资源,另一个线程可以获取到拿到的资源
frameworks/opt/net/wifi/service/java/com/android/server/wifi/WifiHelp.java
/*
* Copyright (C) 2019 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.server.wifi;
import android.annotation.NonNull;
import android.content.Context;
import android.util.Log;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
/**
* Wrapper for context to override getResources method. Resources for wifi mainline jar needs to be
* fetched from the resources APK.
*/
public class WifiHelp {
private static final String TAG = "WifiHelp";
public static FutureTask<Context> mFutureTask;
private static WifiHelp sInstance = null;
private WifiHelp() {
Log.i(TAG, "WifiHelp getInstance construct");
}
public static WifiHelp getInstance() {
Log.i(TAG, "WifiHelp getInstance");
if (sInstance==null){
sInstance=new WifiHelp();
}
Log.i(TAG, "WifiHelp getInstance end, sInstance = " + sInstance);
return sInstance;
}
public Context getContext() {
Log.i(TAG, "getContext, sInstance = " + sInstance + " mFutureTask = " + mFutureTask);
Context context = null;
try {
context = mFutureTask.get();
Log.i(TAG, "getContext, context = " + context);
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
return context;
}
class MyCallable implements Callable<Context> {
private Context mContext;
private static final String WIFI_OVERLAY_JAVA_PKG_NAME = "com.android.wifi.resources";
public MyCallable(@NonNull Context context) {
mContext = context;
Log.i(TAG, "MyCallable construct context = " + context);
}
public Context call() throws Exception {
if (mContext == null) {
Log.i(TAG, "MyCallable, mContext is null");
return null;
}
Log.i(TAG, "MyCallable in thread");
Context result = mContext.createPackageContext(WIFI_OVERLAY_JAVA_PKG_NAME, 0);
Log.i(TAG, "MyCallable in thread, package context = " + result);
return result;
}
}
public void createPackageContext(Context context) {
Log.i(TAG, "createPackageContext, sInstance = " + sInstance + " param context = " + context);
mFutureTask = new FutureTask<>(new MyCallable(context));
new Thread(mFutureTask).start();
Log.i(TAG, "createPackageContext thread start, mFutureTask = " + mFutureTask);
}
}
frameworks/opt/net/wifi/service/java/com/android/server/wifi/WifiContext.java
禁掉直接获取资源,而是调用WifiHelper的获取资源
public Resources getResources() {
if (mWifiResourcesFromApk == null) {
Log.i(TAG, "getResources, mWifiResourcesFromApk is null");
//Context resourcesApkContext = getResourcesApkContext();
Context resourcesApkContext = WifiHelp.getInstance().getContext();
if (resourcesApkContext != null) {
Log.i(TAG, "getResources, mWifiResourcesFromApk is valid");
mWifiResourcesFromApk = resourcesApkContext.getResources();
}
}
return mWifiResourcesFromApk;
}
然后在另一个仓库:
frameworks/base/services/core/java/com/android/server/SystemServiceManager.java
仿照这里的使用反射的函数:startServiceFromJar,通过反射调用到另一个包里,即WifiHelper
public void createWifiContextAhead(String className, String path) {
Slog.i(TAG, "createWifiContextAhead");
PathClassLoader pathClassLoader = mLoadedPaths.get(path);
if (pathClassLoader == null) {
// NB: the parent class loader should always be the system server class loader.
// Changing it has implications that require discussion with the mainline team.
pathClassLoader = new PathClassLoader(path, this.getClass().getClassLoader());
mLoadedPaths.put(path, pathClassLoader);
}
final Class<?> wifiServiceClass = loadClassFromLoader(className, pathClassLoader);
try {
Slog.i(TAG, "createWifiContextAhead, mContext = " + mContext);
Method method = wifiServiceClass.getDeclaredMethod("getInstance", null);
Object service = method.invoke(null, null);
Method method1 = wifiServiceClass.getDeclaredMethod("createPackageContext", Context.class);
method1.invoke(service, mContext);
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
frameworks/base/services/java/com/android/server/SystemServer.java
在startCoreServices之前,是经过验证可以放的地方,太靠前可能会导致wifiscanservice崩溃
// Start services.
try {
t.traceBegin("StartServices");
startBootstrapServices(t);
// put wifiHelp here as is must depend on the packagemanager service up, wangqingyuan
Slog.e("system_server", "wifiContext create ahead of time, avoid wifiservice up consume too much time");
mSystemServiceManager.createWifiContextAhead("com.android.server.wifi.WifiHelp", WIFI_APEX_SERVICE_JAR_PATH);
startCoreServices(t);
startOtherServices(t);
} catch (Throwable ex) {
Slog.e("System", "******************************************");
Slog.e("System", "************ Failure starting system services", ex);
throw ex;
} finally {
t.traceEnd(); // StartServices
}