平台:
RK3288 + android 7.1
问题:
无法在动画过程启动新增加服务.
LOG输出:
01-01 20:00:18.053 686-713/system_process W/ActivityManager: Unable to start
service Intent { act=action pkg=pkgName }
U=0: not found
分析:
|-- frameworks/base/services/java/com/android/server/SystemServer.java
/**
* Starts some essential services that are not tangled up in the bootstrap process.
*/
private void startCoreServices() {
// Tracks the battery level. Requires LightService.
mSystemServiceManager.startService(BatteryService.class);
// Tracks application usage stats.
mSystemServiceManager.startService(UsageStatsService.class);
mActivityManagerService.setUsageStatsManager(
LocalServices.getService(UsageStatsManagerInternal.class));
// Tracks whether the updatable WebView is in a ready state and watches for update installs.
mWebViewUpdateService = mSystemServiceManager.startService(WebViewUpdateService.class);
try{
//Anson MyService Service
mSystemServiceManager.startService(MyService.class);
}catch (Throwable e) {
reportWtf("starting MyService", e);
}
}
新增MyService.java:
|-- frameworks/base/services/core/java/com/android/server/os/MyService.java
public final class MyService extends SystemService implements Handler.Callback {
private static final String TAG = "MyService";
private final Context mContext;
private ServiceThread mHandlerThread;
private Handler mHandler;
private Intent serviceIntent = null;
public MyService(Context context) {
super(context);
mContext = context;
mHandlerThread = new ServiceThread(TAG, android.os.Process.THREAD_PRIORITY_DISPLAY, /*allowTo*/false);
mHandlerThread.start();
mHandler = new Handler(mHandlerThread.getLooper(), this);
}
@Override
public boolean handleMessage(android.os.Message msg) {
switch(msg.what) {
}
return true;
}
@Override
public void onStart(){
Log.d(TAG, "ALog onStart");
}
@Override
public void onBootPhase(int phase) {
//在AM 初始化完成后执行.
if (phase == PHASE_ACTIVITY_MANAGER_READY) {
mHandler.postDelayed(checkService, INTERVAL);
connectToService();
}
}
final int INTERVAL = 1000;
private Runnable checkService = new Runnable(){
public void run(){
if(!isServiceReady()){
mHandler.postDelayed(this, INTERVAL);
connectToService();
}
}
};
private void connectToService(){
Log.d(TAG, "ALog connectToService()");
try{
if(serviceIntent == null){
final Intent bindIntent = new Intent(action);
bindIntent.setComponent(new ComponentName(pkgName, className));
serviceIntent = bindIntent;
}
int flags = Context.BIND_IMPORTANT | Context.BIND_FOREGROUND_SERVICE
| Context.BIND_AUTO_CREATE;
//由这里启动服务
mContext.bindServiceAsUser(serviceIntent, bindConn, flags, android.os.UserHandle.SYSTEM);
}catch(Exception e){
e.printStackTrace();
}
}
//ISystemControler mBinder;
final ServiceConnection bindConn = new ServiceConnection(){
public void onServiceConnected(ComponentName name, android.os.IBinder service){
Log.d(TAG, "ALog onServiceConnected");
mHandler.removeCallbacks(checkService);
//mBinder = ISystemControler.Stub.asInterface(service);
publishBinderService(Context.SYSTEMCTRL_SERVICE, service);
}
public void onServiceDisconnected(ComponentName name){
Log.d(TAG, "ALog onServiceDisconnected");
//mBinder = null;
}
};
private boolean isServiceReady(){
return null != android.os.ServiceManager.checkService(Context.SYSTEMCTRL_SERVICE);
}
}
|-- frameworks/base/services/core/java/com/android/server/am/ActiveServices.java
private ServiceLookupResult retrieveServiceLocked(Intent service,
String resolvedType, String callingPackage, int callingPid, int callingUid, int userId,
boolean createIfNeeded, boolean callingFromFg, boolean isBindExternal) {
ServiceRecord r = null;
if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "retrieveServiceLocked: " + service
+ " type=" + resolvedType + " callingUid=" + callingUid);
userId = mAm.mUserController.handleIncomingUser(callingPid, callingUid, userId, false,
ActivityManagerService.ALLOW_NON_FULL_IN_PROFILE, "service", null);
ServiceMap smap = getServiceMap(userId);
final ComponentName comp = service.getComponent();
if (comp != null) {
r = smap.mServicesByName.get(comp);
}
if (r == null && !isBindExternal) {
Intent.FilterComparison filter = new Intent.FilterComparison(service);
r = smap.mServicesByIntent.get(filter);
}
if (r != null && (r.serviceInfo.flags & ServiceInfo.FLAG_EXTERNAL_SERVICE) != 0
&& !callingPackage.equals(r.packageName)) {
// If an external service is running within its own package, other packages
// should not bind to that instance.
r = null;
}
if (r == null) {
try {
// TODO: come back and remove this assumption to triage all services
ResolveInfo rInfo = AppGlobals.getPackageManager().resolveService(service,
resolvedType, ActivityManagerService.STOCK_PM_FLAGS
| PackageManager.MATCH_DEBUG_TRIAGED_MISSING,
userId);
ServiceInfo sInfo =
rInfo != null ? rInfo.serviceInfo : null;
if (sInfo == null) {
Slog.w(TAG_SERVICE, "Unable to start service " + service + " U=" + userId +
": not found");
return null;
}
问题跟踪:
在MyService.java中加入了服务启动检测, 若不存在, 则在1s 后尝试启动.
在测试过程中发现, 需尝试3次以上才能正常启动.
01-01 20:00:13.042 686-700/system_process D/PackageManager: ALog resolveService Intent { act=action cmp=serviceClass }
ALog queryIntentServicesInternal by comp(ComponentInfo{pkg/cls})
ALog getServiceInfo s != null mSettings.isEnabledAndMatchLPr(s.info, flags, userId) = false.
最终LOG定位到 isEnabledAndMatchLPr 函数执行的返回值, 相关代码如下:
//frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java
@Override
public ResolveInfo resolveService(Intent intent, String resolvedType, int flags, int userId) {
if (!sUserManager.exists(userId)) return null;
d("resolveService " + intent.toString());
flags = updateFlagsForResolve(flags, userId, intent);
List<ResolveInfo> query = queryIntentServicesInternal(intent, resolvedType, flags, userId);
if (query != null) {
if (query.size() >= 1) {
// If there is more than one service with the same priority,
// just arbitrarily pick the first one.
return query.get(0);
}
}
d("resolveService could NOT found");
return null;
}
private @NonNull List<ResolveInfo> queryIntentServicesInternal(Intent intent,
String resolvedType, int flags, int userId) {
...
if (comp != null) {
d("queryIntentServicesInternal by comp(" + comp.toString() + ")");
final List<ResolveInfo> list = new ArrayList<ResolveInfo>(1);
final ServiceInfo si = getServiceInfo(comp, flags, userId);
if (si != null) {
final ResolveInfo ri = new ResolveInfo();
ri.serviceInfo = si;
list.add(ri);
}
return list;
}
..
}
@Override
public ServiceInfo getServiceInfo(ComponentName component, int flags, int userId) {
...
synchronized (mPackages) {
PackageParser.Service s = mServices.mServices.get(component);
if (DEBUG_PACKAGE_INFO) Log.v(
TAG, "getServiceInfo " + component + ": " + s);
d("getServiceInfo flags = " + flags);
if(s == null){
d("getServiceInfo s == null");
}else{
d("getServiceInfo s != null mSettings.isEnabledAndMatchLPr(s.info, flags, userId) = " + (mSettings.isEnabledAndMatchLPr(s.info, flags, userId)));
}
if (s != null && mSettings.isEnabledAndMatchLPr(s.info, flags, userId)) {
PackageSetting ps = mSettings.mPackages.get(component.getPackageName());
if (ps == null) return null;
return PackageParser.generateServiceInfo(s, flags, ps.readUserState(userId),
userId);
}
}
return null;
}
//frameworks/base/services/core/java/com/android/server/pm/Settings.java
boolean isEnabledAndMatchLPr(ComponentInfo componentInfo, int flags, int userId) {
final PackageSetting ps = mPackages.get(componentInfo.packageName);
if (ps == null) return false;
final PackageUserState userState = ps.readUserState(userId);
return userState.isMatch(componentInfo, flags);
}
//frameworks/base/core/java/android/content/pm/PackageUserState.java
/**
* Test if the given component is considered installed, enabled and a match
* for the given flags.
*
* <p>
* Expects at least one of {@link PackageManager#MATCH_DIRECT_BOOT_AWARE} and
* {@link PackageManager#MATCH_DIRECT_BOOT_UNAWARE} are specified in {@code flags}.
* </p>
*/
public boolean isMatch(ComponentInfo componentInfo, int flags) {
if (!isInstalled(flags)) return false;
if (!isEnabled(componentInfo, flags)) return false;
if ((flags & MATCH_SYSTEM_ONLY) != 0) {
if (!componentInfo.applicationInfo.isSystemApp()) {
return false;
}
}
final boolean matchesUnaware = ((flags & MATCH_DIRECT_BOOT_UNAWARE) != 0)
&& !componentInfo.directBootAware;
final boolean matchesAware = ((flags & MATCH_DIRECT_BOOT_AWARE) != 0)
&& componentInfo.directBootAware;
return matchesUnaware || matchesAware;
}
到这里, 意识到跟 flags有点关系, 于是, 打印出了flags的值:
失败:
ALog getServiceInfo flags = 268960768
成功:
ALog getServiceInfo flags = 269222912
有什么区别?
268960768 -> #10080400
269222912 -> #100C0400
两个数的16进制相减为 #40000, 这个FLAG的定义如下:
|--frameworks/base/core/java/android/content/pm/PackageManager.java
/**
* Querying flag: match components which are direct boot <em>unaware</em> in
* the returned info, regardless of the current user state.
* <p>
* When neither {@link #MATCH_DIRECT_BOOT_AWARE} nor
* {@link #MATCH_DIRECT_BOOT_UNAWARE} are specified, the default behavior is
* to match only runnable components based on the user state. For example,
* when a user is started but credentials have not been presented yet, the
* user is running "locked" and only {@link #MATCH_DIRECT_BOOT_AWARE}
* components are returned. Once the user credentials have been presented,
* the user is running "unlocked" and both {@link #MATCH_DIRECT_BOOT_AWARE}
* and {@link #MATCH_DIRECT_BOOT_UNAWARE} components are returned.
*
* @see UserManager#isUserUnlocked()
*/
public static final int MATCH_DIRECT_BOOT_UNAWARE = 0x00040000;
解决:
在新增加服务APK的AndroidManifest.xml中加入
android:directBootAware="true"
如:
...
<application
android:label="@string/app_label"
android:icon="@mipmap/ic_launcher"
android:process="system"
android:directBootAware="true"
android:supportsRtl="true">
...