平台:
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"> ...