Google GMS Crash 优化方案

640?wx_fmt=gif

640?wx_fmt=gif

极力推荐文章:欢迎收藏

Android 干货分享 640?wx_fmt=gif

阅读五分钟,每日十点,和您一起终身学习,这里是程序员Android

GMS(GoogleMobile Service)包是出口国外手机中 Google限制必须要预制的,如果不预置无法过Google CTS 认证,会导致手机无法正常使用,并且Google会对手机厂商进行罚款。Google大牛写的代码也不理我,那么,当我们遇到Google apk Crash 时候我们改如何处理呢?由于没有Google源码,我们不能从根本上解决 Google apk Crash的问题,只能在Android原生的代码上规避 一下Google代码低概率复现问题。

本篇文章主要介绍开发中我们没有源码的GMS Crash崩溃后的解决方案,通过阅读本篇文章,您将收获以下内容:

一、gms.ui Service not registered Crash

一、gms.ui Service not registered Crash

1.Crash Log如下:

--------- beginning of crash
01-01 00:00:16.892  2210  2473 E AndroidRuntime: FATAL EXCEPTION: IPreferenceServiceThread
01-01 00:00:16.892  2210  2473 E AndroidRuntime: Process: com.google.android.gms.ui, PID: 2210
01-01 00:00:16.892  2210  2473 E AndroidRuntime: java.lang.IllegalArgumentException: Service not registered: wfg@202e22a
01-01 00:00:16.892  2210  2473 E AndroidRuntime:    at android.app.LoadedApk.forgetServiceDispatcher(LoadedApk.java:1329)
01-01 00:00:16.892  2210  2473 E AndroidRuntime:    at android.app.ContextImpl.unbindService(ContextImpl.java:1495)
01-01 00:00:16.892  2210  2473 E AndroidRuntime:    at android.content.ContextWrapper.unbindService(ContextWrapper.java:648)
01-01 00:00:16.892  2210  2473 E AndroidRuntime:    at android.content.ContextWrapper.unbindService(ContextWrapper.java:648)
01-01 00:00:16.892  2210  2473 E AndroidRuntime:    at android.content.ContextWrapper.unbindService(ContextWrapper.java:648)
01-01 00:00:16.892  2210  2473 E AndroidRuntime:    at android.content.ContextWrapper.unbindService(ContextWrapper.java:648)
01-01 00:00:16.892  2210  2473 E AndroidRuntime:    at msl.a(:com.google.android.gms@11951440:39)
01-01 00:00:16.892  2210  2473 E AndroidRuntime:    at wfh.run(:com.google.android.gms@11951440:5)
--------- beginning of system
2.Crash 原因:

当绑定服务已经解除绑定,再次解除绑定,会出现此异常。

640?wx_fmt=other

当绑定服务已经解除绑定,再次解除绑定,会出现此异常

3.解决方案:

由于没有GMS源码,我们不能从根源上处理问题,只能尝试修改Framework代码规避此问题。

frameworks/base/core/java/android/app/ContextImpl.java
frameworks/base/core/java/android/content/ContextWrapper.java

修改1:ContextWrapper.java

ContextWrapperunbindService 方法中try-catch住代码中抛出的异常IllegalArgumentException,抓住异常,不让异常抛出。

   
public class ContextWrapper extends Context {
    ... ...
    
    @Override
      public void unbindService(ServiceConnection conn) {
          try {
                 mBase.unbindService(conn);
              } catch (IllegalArgumentException e) {
                //com.google.android.gms.ui Service not registered Crash
                android.util.Log.e("wjwj","---ContextWrapper GMS Crash---");
                e.printStackTrace();
          }
      }
   
    ... ...
    
}

640?wx_fmt=other

在ContextWrapper的 unbindService 方法中try-catch IllegalArgumentException

修改2:ContextImpl.java

修改方法如下:


 class ReceiverRestrictedContext extends ContextWrapper {
      ... ...
      
      @Override
      public void unbindService(ServiceConnection conn) {
          if (conn == null) {
              throw new IllegalArgumentException("connection is null");
          }
          if (mPackageInfo != null) {
              IServiceConnection sd = mPackageInfo.forgetServiceDispatcher(
                      getOuterContext(), conn);
              try {
                  ActivityManager.getService().unbindService(sd);
              } catch (RemoteException e) {
                  throw e.rethrowFromSystemServer();
              } catch (IllegalArgumentException e) {
                  //com.google.android.gms.ui Service not registered Crash
                                  android.util.Log.e("wjwj","---ContextImpl GMS Crash---");
                  e.printStackTrace();
              }
  
          } else {
              throw new RuntimeException("Not supported in system context");
          }
      }
      ... ...

}

修改思路:ContextImplunbindService 方法中try-catch抓住代码中抛出的异常IllegalArgumentException

640?wx_fmt=other

在ContextImpl的unbindService 方法中try-catch IllegalArgumentException

二、gms.ui BadTokenException Crash

1.Crash Log如下:

12-31 21:01:26.711  3776  3776 E AndroidRuntime: FATAL EXCEPTION: main
12-31 21:01:26.711  3776  3776 E AndroidRuntime: Process: com.google.android.gms.ui, PID: 3776
12-31 21:01:26.711  3776  3776 E AndroidRuntime: android.view.WindowManager$BadTokenException:
                                                  Unable to add window -- token android.os.BinderProxy@f176911 is not valid; is your activity running?
12-31 21:01:26.711  3776  3776 E AndroidRuntime:    at android.view.ViewRootImpl.setView(ViewRootImpl.java:567)
12-31 21:01:26.711  3776  3776 E AndroidRuntime:    at android.view.WindowManagerGlobal.addView(WindowManagerGlobal.java:310)
12-31 21:01:26.711  3776  3776 E AndroidRuntime:    at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:85)
12-31 21:01:26.711  3776  3776 E AndroidRuntime:    at android.app.Dialog.show(Dialog.java:319)
12-31 21:01:26.711  3776  3776 E AndroidRuntime:    at com.google.android.location.network.ConfirmAlertChimeraActivity.a(:com.google.android.gms:164)
12-31 21:01:26.711  3776  3776 E AndroidRuntime:    at rzo.onServiceConnected(:com.google.android.gms:71)
12-31 21:01:26.711  3776  3776 E AndroidRuntime:    at android.app.LoadedApk$ServiceDispatcher.doConnected(LoadedApk.java:1223)

640?wx_fmt=other

Unable to add window -- token android.os.BinderProxy@f176911 is not valid; is your activity running

2.解决方案如下

主要修改类:frameworks/base/core/java/android/view/ViewRootImpl.java

在 ViewRootImpl类中,解决恢复出厂设置后的问题,修改方案如下:

   
 public class ViewRootImpl extends AbsViewRootImpl implements ViewParent,
           View.AttachInfo.Callbacks, ThreadedRenderer.DrawCallbacks {
 
            ... ...
         
        public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
          synchronized (this) {
               if (mView == null) {
                   mView = view;
              ... ...
 
                if (res < WindowManagerGlobal.ADD_OKAY) {
                       mAttachInfo.mRootView = null;
                       mAdded = false;
                       mFallbackEventHandler.setView(null);
                       unscheduleTraversals();
                       setAccessibilityFocus(null, null);
                       switch (res) {
                           case WindowManagerGlobal.ADD_BAD_APP_TOKEN:
                           case WindowManagerGlobal.ADD_BAD_SUBWINDOW_TOKEN:
                               // add by wangjie for com.google.android.gms.ui crash
                               int deviceProvisioned = android.provider.Settings.Global.getInt(mContext.getContentResolver(), android.provider.Settings.Global.DEVICE_PROVISIONED,0);
                               if(deviceProvisioned==0){
                                  android.util.Log.e("wjwj","---ViewRootImpl GMS Crash---");
                                  return;
                               }else{
                                   throw new WindowManager.BadTokenException(
                                        "Unable to add window -- token " + attrs.token
                                        + " is not valid; is your activity running?");
                               }
                               // add by wangjie for com.google.android.gms.ui crash
                           case WindowManagerGlobal.ADD_NOT_APP_TOKEN:
                               throw new WindowManager.BadTokenException(
                                       "Unable to add window -- token " + attrs.token
                                       + " is not for an application");
                      ... ...
               }
           }
       }
                ... ...
}

修改差异点如下

640?wx_fmt=other

Unable to add window -- token android.os.BinderProxy@f176911 is not valid; is your activity running?

三、setupwizard ConcurrentModificationException Crash

1.Crash Log如下:

--------- beginning of crash
01-01 12:00:00.918  1583  1583 E AndroidRuntime: FATAL EXCEPTION: main
01-01 12:00:00.918  1583  1583 E AndroidRuntime: Process: com.google.android.setupwizard, PID: 1583
01-01 12:00:00.918  1583  1583 E AndroidRuntime: java.lang.RuntimeException: Error receiving broadcast Intent { act=android.intent.action.TIME_SET flg=0x25200010 } in com.google.android.setupwizard.time.DateTimeMonitor$1@7465601
01-01 12:00:00.918  1583  1583 E AndroidRuntime:    at android.app.LoadedApk$ReceiverDispatcher$Args.lambda$-android_app_LoadedApk$ReceiverDispatcher$Args_52497(LoadedApk.java:1323)
01-01 12:00:00.918  1583  1583 E AndroidRuntime:    at android.app.-$Lambda$aS31cHIhRx41653CMnd4gZqshIQ.$m$7(Unknown Source:4)
01-01 12:00:00.918  1583  1583 E AndroidRuntime:    at android.app.-$Lambda$aS31cHIhRx41653CMnd4gZqshIQ.run(Unknown Source:39)
01-01 12:00:00.918  1583  1583 E AndroidRuntime:    at android.os.Handler.handleCallback(Handler.java:790)
01-01 12:00:00.918  1583  1583 E AndroidRuntime:    at android.os.Handler.dispatchMessage(Handler.java:99)
01-01 12:00:00.918  1583  1583 E AndroidRuntime:    at android.os.Looper.loop(Looper.java:164)
01-01 12:00:00.918  1583  1583 E AndroidRuntime:    at android.app.ActivityThread.main(ActivityThread.java:6523)
01-01 12:00:00.918  1583  1583 E AndroidRuntime:    at java.lang.reflect.Method.invoke(Native Method)
01-01 12:00:00.918  1583  1583 E AndroidRuntime:    at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:438)
01-01 12:00:00.918  1583  1583 E AndroidRuntime:    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:857)
01-01 12:00:00.918  1583  1583 E AndroidRuntime: Caused by: java.util.ConcurrentModificationException
01-01 12:00:00.918  1583  1583 E AndroidRuntime:    at java.util.ArrayList$Itr.next(ArrayList.java:860)
01-01 12:00:00.918  1583  1583 E AndroidRuntime:    at com.google.android.setupwizard.time.DateTimeMonitor.updateStatus(DateTimeMonitor.java:134)
01-01 12:00:00.918  1583  1583 E AndroidRuntime:    at com.google.android.setupwizard.time.DateTimeMonitor.-wrap0(Unknown Source:0)
01-01 12:00:00.918  1583  1583 E AndroidRuntime:    at com.google.android.setupwizard.time.DateTimeMonitor$1.onReceive(DateTimeMonitor.java:73)
01-01 12:00:00.918  1583  1583 E AndroidRuntime:    at android.app.LoadedApk$ReceiverDispatcher$Args.lambda$-android_app_LoadedApk$ReceiverDispatcher$Args_52497(LoadedApk.java:1313)
01-01 12:00:00.918  1583  1583 E AndroidRuntime:    ... 9 more
--------- beginning of system

640?wx_fmt=other

ConcurrentModificationException

2.解决方案如下:

此问题关键在于解决ConcurrentModificationException,但是没有GMS源码,只能尝试规避方案。/frameworks/base/core/java/android/app/LoadedApk.java

修改点如下:

 public final class LoadedApk {
     ... ...

        final class Args extends BroadcastReceiver.PendingResult {


              public final Runnable getRunnable() {

               ... ...
  
                      Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "broadcastReceiveReg");
                      try {
                          ClassLoader cl = mReceiver.getClass().getClassLoader();
                          intent.setExtrasClassLoader(cl);
                          intent.prepareToEnterProcess();
                          setExtrasClassLoader(cl);
                          receiver.setPendingResult(this);
                          receiver.onReceive(mContext, intent);
                      } catch (Exception e) {
                          if (mRegistered && ordered) {
                              if (ActivityThread.DEBUG_BROADCAST) Slog.i(ActivityThread.TAG,
                                      "Finishing failed broadcast to " + mReceiver);
                              sendFinished(mgr);
                          }
                          if (mInstrumentation == null ||
                                  !mInstrumentation.onException(mReceiver, e)) {
                              Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                              //setupwizard TIME_SET RuntimeException Crash
                              if("android.intent.action.TIME_SET".equals(intent.getAction())){
                                  if(mReceiver.toString().contains("com.google.android.setupwizard")){
                                      android.util.Log.e("wjwj","---LoadedApk GMS  setupwizard Crash---");
                                      return;
                                  }
                              }
                              //setupwizard TIME_SET RuntimeException Crash
                              throw new RuntimeException(
                                      "Error receiving broadcast " + intent
                                              + " in " + mReceiver, e);
                          }
                      }
                             ... ...
                  };
              }
          }
     
     ... ...

}

修改差异点如下:

640?wx_fmt=other

throw new RuntimeException 异常没有被try-catch 导致crash

四、setupwizard ActivityNotFoundException Crash

1.Crash Log如下:

--------- beginning of crash
12-12 15:19:11.984  1471  1471 E AndroidRuntime: FATAL EXCEPTION: main
12-12 15:19:11.984  1471  1471 E AndroidRuntime: Process: com.google.android.setupwizard, PID: 1471
12-12 15:19:11.984  1471  1471 E AndroidRuntime: android.content.ActivityNotFoundException: No Activity found to handle Intent { act=com.android.wizard.NEXT (has extras) }
12-12 15:19:11.984  1471  1471 E AndroidRuntime:    at android.app.Instrumentation.checkStartActivityResult(Instrumentation.java:1843)
12-12 15:19:11.984  1471  1471 E AndroidRuntime:    at android.app.Instrumentation.execStartActivity(Instrumentation.java:1557)
12-12 15:19:11.984  1471  1471 E AndroidRuntime:    at android.app.Activity.startActivityForResult(Activity.java:4228)
12-12 15:19:11.984  1471  1471 E AndroidRuntime:    at android.app.Activity.startActivityForResult(Activity.java:4187)
12-12 15:19:11.984  1471  1471 E AndroidRuntime:    at com.google.android.setupwizard.BaseActivity.startActivityForResult(BaseActivity.java:665)
12-12 15:19:11.984  1471  1471 E AndroidRuntime:    at com.google.android.setupwizard.BaseActivity.nextAction(BaseActivity.java:651)
12-12 15:19:11.984  1471  1471 E AndroidRuntime:    at com.google.android.setupwizard.BaseActivity.nextAction(BaseActivity.java:637)
12-12 15:19:11.984  1471  1471 E AndroidRuntime:    at com.google.android.setupwizard.user.SuggestedActionsActivity.onItemSelected(SuggestedActionsActivity.java:226)
12-12 15:19:11.984  1471  1471 E AndroidRuntime:    at com.android.setupwizardlib.items.RecyclerItemAdapter$1.onClick(RecyclerItemAdapter.java:106)
12-12 15:19:11.984  1471  1471 E AndroidRuntime:    at android.view.View.performClick(View.java:5624)
12-12 15:19:11.984  1471  1471 E AndroidRuntime:    at android.view.View$PerformClick.run(View.java:22285)

640?wx_fmt=other

com.google.android.setupwizard 报错log

2.解决方案如下:

Instrumentation类中对Google开机向导进行特殊处理。/frameworks/base/core/java/android/app/Instrumentation.java

public class Instrumentation {

      ... ...

      /** @hide */
      public static void checkStartActivityResult(int res, Object intent) {
          if (!ActivityManager.isStartResultFatalError(res)) {
              return;
          }
  
          switch (res) {
              case ActivityManager.START_INTENT_NOT_RESOLVED:
              case ActivityManager.START_CLASS_NOT_FOUND:
                  if (intent instanceof Intent && ((Intent)intent).getComponent() != null)
                      throw new ActivityNotFoundException(
                              "Unable to find explicit activity class "
                              + ((Intent)intent).getComponent().toShortString()
                              + "; have you declared this activity in your AndroidManifest.xml?");
                                  //GMS  Setupwizard ActivityNotFoundException Crash
                  if("com.android.wizard.NEXT".equals(((Intent)intent).getAction())){
                      android.util.Log.e("wjwj","Instrumentation  GMS  Setupwizard Crash ");
                      return;
                  }
                  //GMS  Setupwizard ActivityNotFoundException Crash
                  throw new ActivityNotFoundException(
                          "No Activity found to handle " + intent);
              case ActivityManager.START_PERMISSION_DENIED:
                  throw new SecurityException("Not allowed to start activity "
                          + intent);
              case ActivityManager.START_FORWARD_AND_REQUEST_CONFLICT:
                  throw new AndroidRuntimeException(
                          "FORWARD_RESULT_FLAG used while also requesting a result");
              case ActivityManager.START_NOT_ACTIVITY:
                  throw new IllegalArgumentException(
                          "PendingIntent is not an activity");
                 ... ...
                 }
            }
           ... ...
}

主要修改差异点如下:

640?wx_fmt=other

Instrumentation 类中对Google 开机向导进行特殊处理下

五、setupwizard On-body ActivityNotFoundException Crash

1.Crash Log如下:

--------- beginning of crash
12-31 19:00:26.668  2010  2010 E AndroidRuntime: FATAL EXCEPTION: main
12-31 19:00:26.668  2010  2010 E AndroidRuntime: Process: com.google.android.setupwizard, PID: 2010
12-31 19:00:26.668  2010  2010 E AndroidRuntime: android.content.ActivityNotFoundException: Unable to find explicit activity class {com.google.android.gms/com.google.android.gms.trustagent.discovery.OnbodyPromotionActivity}; have you declared this activity in your AndroidManifest.xml?
12-31 19:00:26.668  2010  2010 E AndroidRuntime:    at android.app.Instrumentation.checkStartActivityResult(Instrumentation.java:1805)
12-31 19:00:26.668  2010  2010 E AndroidRuntime:    at android.app.Instrumentation.execStartActivity(Instrumentation.java:1523)
12-31 19:00:26.668  2010  2010 E AndroidRuntime:    at android.app.Activity.startActivityForResult(Activity.java:4229)
12-31 19:00:26.668  2010  2010 E AndroidRuntime:    at android.app.Activity.startActivityForResult(Activity.java:4188)
12-31 19:00:26.668  2010  2010 E AndroidRuntime:    at com.google.android.setupwizard.BaseActivity.startActivityForResult(BaseActivity.java:665)
12-31 19:00:26.668  2010  2010 E AndroidRuntime:    at com.google.android.setupwizard.BaseActivity.startFirstRunActivityForResult(BaseActivity.java:719)
12-31 19:00:26.668  2010  2010 E AndroidRuntime:    at com.google.android.setupwizard.user.SuggestedActionsActivity.onItemSelected(SuggestedActionsActivity.java:217)
12-31 19:00:26.668  2010  2010 E AndroidRuntime:    at com.android.setupwizardlib.items.RecyclerItemAdapter$1.onClick(RecyclerItemAdapter.java:106)
12-31 19:00:26.668  2010  2010 E AndroidRuntime:    at android.view.View.performClick(View.java:5675)
12-31 19:00:26.668  2010  2010 E AndroidRuntime:    at android.view.View$PerformClick.run(View.java:22641)
12-31 19:00:26.668  2010  2010 E AndroidRuntime:    at android.os.Handler.handleCallback(Handler.java:836)
12-31 19:00:26.668  2010  2010 E AndroidRuntime:    at android.os.Handler.dispatchMessage(Handler.java:103)
12-31 19:00:26.668  2010  2010 E AndroidRuntime:    at android.os.Looper.loop(Looper.java:203)

640?wx_fmt=other

Unable to find explicit activity class Log

2.解决方案如下:

640?wx_fmt=other

com.google.android.setupwizard 解决方案

六、Google play Service NullPointerException Crash

1.Crash log

Google play Service 空指针的Log由于目前没有找到,后续补上。

2.解决方案如下:

主要修改类:frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java

 public class PackageManagerService extends PackageManagerServiceExAbs
          implements PackageSender {

 /**
      * Important: The provided filterCallingUid is used exclusively to filter out activities
      * that can be seen based on user state. It's typically the original caller uid prior
      * to clearing. Because it can only be provided by trusted code, it's value can be
      * trusted and will be used as-is; unlike userId which will be validated by this method.
      */
     private ActivityInfo getActivityInfoInternal(ComponentName component, int flags,
             int filterCallingUid, int userId) {
         boolean isAppClone = false;
         if (component != null && AppCloneUserInfo.containsCloneTag(component.getPackageName())) {
             userId = AppCloneUserInfo.getUserIdFromCloneTag(component.getPackageName(), userId);
             final String packageName = AppCloneUserInfo.removeCloneTag(component.getPackageName());
             final String className = component.getClassName();
             component = new ComponentName(packageName, className);
             isAppClone = true;
         }
         if (!sUserManager.exists(userId)) return null;
         flags = updateFlagsForComponent(flags, userId, component);
         enforceCrossUserPermission(Binder.getCallingUid(), userId,
                 false /* requireFullPermission */, false /* checkShell */, "get activity info");
         synchronized (mPackages) {
             PackageParser.Activity a = mActivities.mActivities.get(component);
 
             if (DEBUG_PACKAGE_INFO) Log.v(TAG, "getActivityInfo " + component + ": " + a);
             if (a != null) {
                 // SPRD: Add for AppClone (Components), generate activity info of owner.
                 int lastUserId = userId;
                 if(!mSettings.isEnabledAndMatchLPr(a.info, flags, userId)) {
                     lastUserId = AppCloneUserInfo.adjustAppCloneUserId(
                             a.info.applicationInfo, userId);
                 }
                 if (mSettings.isEnabledAndMatchLPr(a.info, flags, lastUserId)) {
                     PackageSetting ps = mSettings.mPackages.get(component.getPackageName());
                     if (ps == null) return null;
                     if (filterAppAccessLPr(ps, filterCallingUid, component, TYPE_ACTIVITY, lastUserId)) {
                         return null;
                     }
                     /* SPRD: modify to distinguish package of appclone @{ */
                     /*return PackageParser.generateActivityInfo(a, flags, ps.readUserState(userId),
                             userId);*/
                     ActivityInfo info = PackageParser.generateActivityInfo(a, flags, ps.readUserState(lastUserId),
                             lastUserId);
                     if (info != null && isAppClone) {
                         info.packageName = AppCloneUserInfo.addCloneTag(info.packageName, lastUserId);
                     }
                     return info;
                     /* @} */
                 }
             }
             // GMS  Google play Service NullPointerException Crash
             if (null != mResolveComponentName && mResolveComponentName.equals(component)) {
                 android.util.Log.e("wjwj","PackageManageServices GMS Google play Service NullPointerException Crash ");
             //      GMS  Google play Service NullPointerException Crash
                 /* SPRD: modify to distinguish package of appclone @{ */
                 /*return PackageParser.generateActivityInfo(
                         mResolveActivity, flags, new PackageUserState(), userId);*/
                 ActivityInfo info = PackageParser.generateActivityInfo(
                         mResolveActivity, flags, new PackageUserState(), userId);
                 if (info != null && isAppClone) {
                     info.packageName = AppCloneUserInfo.addCloneTag(info.packageName, userId);
                 }
                 return info;
                 /* @} */
             }
         }
         return null;
     }



}

Google play Service NullPointerException Crash主要修改点如下:

640?wx_fmt=other

Google play Service NullPointerException Crash主要修改点

七、恢复出厂设置或者第一次开机,先闪壁纸再显示开机向导

解决方案如下:

主要修改KeyguardServiceDelegate这个类。frameworks/base/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java

  • 1.修改点1:

在此类中添加判断方法,获取手机DEVICE_PROVISIONED状态信息。

640?wx_fmt=other

在此类中添加判断方法

-2. 修改点2:

此类的构造方法中,如果获取到的为true,先隐藏

640?wx_fmt=other

此类的构造方法中,如果获取到的为true,先隐藏

  • 3.修改点3:

onScreenTurningOn 中判断显示

640?wx_fmt=other

onScreenTurningOn 中判断显示

640?wx_fmt=other

系统原生显示与隐藏方法

640?wx_fmt=png

坚持就有惊喜

posted @ 2019-08-13 12:10  程序员Android的博客  阅读(236)  评论(0编辑  收藏  举报