华为9.0无限奔溃问题java.lang.NullPointerException:Attempt to invoke virtual method 'void android.app.FragmentController.attachHost

Posted by on February 14, 2019
  • 好多用户反馈说app在华为9.0系统上无法打开APP,于是自己运行没问题,然后从应用市场下载下来安装果然GG

  • 问题排查看到的奔溃日志如下:

    java.lang.RuntimeException: Unable to start activity ComponentInfo{com.bdqn.kegongchang/xxxx.ui.activity.ActivitySplash}: java.lang.NullPointerException: Attempt to invoke virtual method ‘void android.app.FragmentController.attachHost(android.app.Fragment)’ on a null object reference at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3300) at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3484) at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:86) at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:108) at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:68) at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2123) at android.os.Handler.dispatchMessage(Handler.java:109) at android.os.Looper.loop(Looper.java:207) at android.app.ActivityThread.main

从奔溃日志中可以看到应该是在ActivityThreadperformLaunchActivity方法中调用FragmentController.attachHost方法FragmentController为空造成的空指针,由于是9.0我们查看9.0的源码,首先看看ActivityThreadperformLaunchActivity方法中奔溃位置

 private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
2809        ActivityInfo aInfo = r.activityInfo;
2810        if (r.packageInfo == null) {
2811            r.packageInfo = getPackageInfo(aInfo.applicationInfo, r.compatInfo,
2812                    Context.CONTEXT_INCLUDE_CODE);
2813        }
2814
2815        ComponentName component = r.intent.getComponent();
2816        if (component == null) {
2817            component = r.intent.resolveActivity(
2818                mInitialApplication.getPackageManager());
2819            r.intent.setComponent(component);
2820        }
2821
2822        if (r.activityInfo.targetActivity != null) {
2823            component = new ComponentName(r.activityInfo.packageName,
2824                    r.activityInfo.targetActivity);
2825        }
2826
2827        ContextImpl appContext = createBaseContextForActivity(r);
2828        Activity activity = null;
2829        try {
2830            java.lang.ClassLoader cl = appContext.getClassLoader();
2831            activity = mInstrumentation.newActivity(
2832                    cl, component.getClassName(), r.intent);
2833            StrictMode.incrementExpectedActivityCount(activity.getClass());
2834            r.intent.setExtrasClassLoader(cl);
2835            r.intent.prepareToEnterProcess();
2836            if (r.state != null) {
2837                r.state.setClassLoader(cl);
2838            }
2839        } catch (Exception e) {
2840            if (!mInstrumentation.onException(activity, e)) {
2841                throw new RuntimeException(
2842                    "Unable to instantiate activity " + component
2843                    + ": " + e.toString(), e);
2844            }
2845        }
2846
2847        try {
2848            Application app = r.packageInfo.makeApplication(false, mInstrumentation);
2849
2850            if (localLOGV) Slog.v(TAG, "Performing launch of " + r);
2851            if (localLOGV) Slog.v(
2852                    TAG, r + ": app=" + app
2853                    + ", appName=" + app.getPackageName()
2854                    + ", pkg=" + r.packageInfo.getPackageName()
2855                    + ", comp=" + r.intent.getComponent().toShortString()
2856                    + ", dir=" + r.packageInfo.getAppDir());
2857
2858            if (activity != null) {
2859                CharSequence title = r.activityInfo.loadLabel(appContext.getPackageManager());
2860                Configuration config = new Configuration(mCompatConfiguration);
2861                if (r.overrideConfig != null) {
2862                    config.updateFrom(r.overrideConfig);
2863                }
2864                if (DEBUG_CONFIGURATION) Slog.v(TAG, "Launching activity "
2865                        + r.activityInfo.name + " with config " + config);
2866                Window window = null;
2867                if (r.mPendingRemoveWindow != null && r.mPreserveWindow) {
2868                    window = r.mPendingRemoveWindow;
2869                    r.mPendingRemoveWindow = null;
2870                    r.mPendingRemoveWindowManager = null;
2871                }
2872                appContext.setOuterContext(activity);
2873                activity.attach(appContext, this, getInstrumentation(), r.token,
2874                        r.ident, app, r.intent, r.activityInfo, title, r.parent,
2875                        r.embeddedID, r.lastNonConfigurationInstances, config,
2876                        r.referrer, r.voiceInteractor, window, r.configCallback);
2877
2878                if (customIntent != null) {
2879                    activity.mIntent = customIntent;
2880                }
2881                r.lastNonConfigurationInstances = null;
2882                checkAndBlockForNetworkAccess();
2883                activity.mStartedActivity = false;
2884                int theme = r.activityInfo.getThemeResource();
2885                if (theme != 0) {
2886                    activity.setTheme(theme);
2887                }
2888
2889                activity.mCalled = false;
2890                if (r.isPersistable()) {
2891                    mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);
2892                } else {
2893                    mInstrumentation.callActivityOnCreate(activity, r.state);
2894                }
2895                if (!activity.mCalled) {
2896                    throw new SuperNotCalledException(
2897                        "Activity " + r.intent.getComponent().toShortString() +
2898                        " did not call through to super.onCreate()");
2899                }
2900                r.activity = activity;
2901            }
2902            r.setState(ON_CREATE);
2903
2904            mActivities.put(r.token, r);
2905
2906        } catch (SuperNotCalledException e) {
2907            throw e;
2908
2909        } catch (Exception e) {
2910            if (!mInstrumentation.onException(activity, e)) {
2911                throw new RuntimeException(
2912                    "Unable to start activity " + component
2913                    + ": " + e.toString(), e);
2914            }
2915        }
2916
2917        return activity;
2918    }
2919

从最后面的catch可以看到奔溃的位置应该是在2847下面其中某行,这里就不卖关子奔溃的具体位置是在2873行的 activity.attach方法中,我们进去看看

  final void attach(Context context, ActivityThread aThread,
7045            Instrumentation instr, IBinder token, int ident,
7046            Application application, Intent intent, ActivityInfo info,
7047            CharSequence title, Activity parent, String id,
7048            NonConfigurationInstances lastNonConfigurationInstances,
7049            Configuration config, String referrer, IVoiceInteractor voiceInteractor,
7050            Window window, ActivityConfigCallback activityConfigCallback) {
7051        attachBaseContext(context);
7052
7053        mFragments.attachHost(null /*parent*/);
7054
7055        mWindow = new PhoneWindow(this, window, activityConfigCallback);
7056        mWindow.setWindowControllerCallback(this);
7057        mWindow.setCallback(this);
7058        mWindow.setOnWindowDismissedCallback(this);
7059        mWindow.getLayoutInflater().setPrivateFactory(this);
7060        if (info.softInputMode != WindowManager.LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED) {
7061            mWindow.setSoftInputMode(info.softInputMode);
7062        }
7063        if (info.uiOptions != 0) {
7064            mWindow.setUiOptions(info.uiOptions);
7065        }
7066        mUiThread = Thread.currentThread();
7067
7068        mMainThread = aThread;
7069        mInstrumentation = instr;
7070        mToken = token;
7071        mIdent = ident;
7072        mApplication = application;
7073        mIntent = intent;
7074        mReferrer = referrer;
7075        mComponent = intent.getComponent();
7076        mActivityInfo = info;
7077        mTitle = title;
7078        mParent = parent;
7079        mEmbeddedID = id;
7080        mLastNonConfigurationInstances = lastNonConfigurationInstances;
7081        if (voiceInteractor != null) {
7082            if (lastNonConfigurationInstances != null) {
7083                mVoiceInteractor = lastNonConfigurationInstances.voiceInteractor;
7084            } else {
7085                mVoiceInteractor = new VoiceInteractor(voiceInteractor, this, this,
7086                        Looper.myLooper());
7087            }
7088        }
7089
7090        mWindow.setWindowManager(
7091                (WindowManager)context.getSystemService(Context.WINDOW_SERVICE),
7092                mToken, mComponent.flattenToString(),
7093                (info.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0);
7094        if (mParent != null) {
7095            mWindow.setContainer(mParent.getWindow());
7096        }
7097        mWindowManager = mWindow.getWindowManager();
7098        mCurrentConfig = config;
7099
7100        mWindow.setColorMode(info.colorMode);
7101
7102        setAutofillCompatibilityEnabled(application.isAutofillCompatibilityEnabled());
7103        enableAutofillCompatibilityIfNeeded();
7104    }
7105
7106    private void enableAutofillCompatibilityIfNeeded() {
7107        if (isAutofillCompatibilityEnabled()) {
7108            final AutofillManager afm = getSystemService(AutofillManager.class);
7109            if (afm != null) {
7110                afm.enableCompatibilityMode();
7111            }
7112        }
7113    }

我们看到在7053行找到了奔溃的位置,那么mFragments他是什么,他在什么时候初始化的

832    final FragmentController mFragments = FragmentController.createController(new HostCallbacks());

activity的832行看到他是个成员变量activity创建的时候一起创建了,按道理说这里应该不可能为空啊,到这里没有其他思路了,我们还有一个APP没问题,想到能不能看看有啥区别,最终发现是集成的FragmentActivity而我们奔溃的是APP是继承与actiivity这个项目比较老,有没有可能是这问题,于是看看FragmentActivity

   protected void onCreate(@Nullable Bundle savedInstanceState) {
323        mFragments.attachHost(null /*parent*/);
324
325        super.onCreate(savedInstanceState);
326
327        NonConfigurationInstances nc =
328                (NonConfigurationInstances) getLastNonConfigurationInstance();
329        if (nc != null) {
330            mViewModelStore = nc.viewModelStore;
331        }
332        if (savedInstanceState != null) {
333            Parcelable p = savedInstanceState.getParcelable(FRAGMENTS_TAG);
334            mFragments.restoreAllState(p, nc != null ? nc.fragments : null);
335
336            // Check if there are any pending onActivityResult calls to descendent Fragments.
337            if (savedInstanceState.containsKey(NEXT_CANDIDATE_REQUEST_INDEX_TAG)) {
338                mNextCandidateRequestIndex =
339                        savedInstanceState.getInt(NEXT_CANDIDATE_REQUEST_INDEX_TAG);
340                int[] requestCodes = savedInstanceState.getIntArray(ALLOCATED_REQUEST_INDICIES_TAG);
341                String[] fragmentWhos = savedInstanceState.getStringArray(REQUEST_FRAGMENT_WHO_TAG);
342                if (requestCodes == null || fragmentWhos == null ||
343                            requestCodes.length != fragmentWhos.length) {
344                    Log.w(TAG, "Invalid requestCode mapping in savedInstanceState.");
345                } else {
346                    mPendingFragmentActivityResults = new SparseArrayCompat<>(requestCodes.length);
347                    for (int i = 0; i < requestCodes.length; i++) {
348                        mPendingFragmentActivityResults.put(requestCodes[i], fragmentWhos[i]);
349                    }
350                }
351            }
352        }
353
354        if (mPendingFragmentActivityResults == null) {
355            mPendingFragmentActivityResults = new SparseArrayCompat<>();
356            mNextCandidateRequestIndex = 0;
357        }
358
359        mFragments.dispatchCreate();
360    }

FragmentActivity我们发现他调用 mFragments.attachHost(null /*parent*/);是在onCreate中,而activity是在attch中,他初始化FragmentController也是在创建的时候初始化的,看到这里应该没啥区别了,就是初始化时机不一样,到此问题原因分析完了,但是具体怎么导致的确实没找到,我们换成FragmentActivity成功解决,这里目前只能说是华为room存在一定适配问题。