暂时未有相关云产品技术能力~
概述本文续自:Android 11 的状态栏的隐藏PS本文虽然同属于SystemUI, 但目前并 没有 打算整理成专橍或撰写一个系列的想法.仅仅为了记录一些过程, 留下那些容易被遗忘的点滴.开始下拉时状态栏图标被隐藏 状态橍的图标在用户开始触摸(ACTION_DOWN)后, 会开始展开, 显示扩展面板, 同时, 隐藏状态橍上的通知和状态图标. 在手机上表现有可能不同, 在android 13上, 在点击没有作用, 只有下拉一定的距离,才会开始隐藏.device-2022-12-21-190046隐藏从触摸下按开始, 参照下图:忽略过程代码, 直接上最后一部分:frameworks/base/packages/SystemUI//src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragment.java@Override public void disable(int displayId, int state1, int state2, boolean animate) { if (displayId != getContext().getDisplayId()) { return; } state1 = adjustDisableFlags(state1); final int old1 = mDisabled1; final int diff1 = state1 ^ old1; mDisabled1 = state1; if ((diff1 & DISABLE_SYSTEM_INFO) != 0) { if ((state1 & DISABLE_SYSTEM_INFO) != 0) { hideSystemIconArea(animate); hideOperatorName(animate); } else { showSystemIconArea(animate); showOperatorName(animate); } } if ((diff1 & DISABLE_NOTIFICATION_ICONS) != 0) { if ((state1 & DISABLE_NOTIFICATION_ICONS) != 0) { hideNotificationIconArea(animate); } else { showNotificationIconArea(animate); } } // The clock may have already been hidden, but we might want to shift its // visibility to GONE from INVISIBLE or vice versa if ((diff1 & DISABLE_CLOCK) != 0 || mClockView.getVisibility() != clockHiddenMode()) { if ((state1 & DISABLE_CLOCK) != 0) { hideClock(animate); } else { showClock(animate); } } } protected int adjustDisableFlags(int state) { boolean headsUpVisible = mStatusBarComponent.headsUpShouldBeVisible(); if (headsUpVisible) { state |= DISABLE_CLOCK; } if (!mKeyguardStateController.isLaunchTransitionFadingAway() && !mKeyguardStateController.isKeyguardFadingAway() && shouldHideNotificationIcons() && !(mStatusBarStateController.getState() == StatusBarState.KEYGUARD && headsUpVisible)) { state |= DISABLE_NOTIFICATION_ICONS; state |= DISABLE_SYSTEM_INFO; state |= DISABLE_CLOCK; } if (mNetworkController != null && EncryptionHelper.IS_DATA_ENCRYPTED) { if (mNetworkController.hasEmergencyCryptKeeperText()) { state |= DISABLE_NOTIFICATION_ICONS; } if (!mNetworkController.isRadioOn()) { state |= DISABLE_SYSTEM_INFO; } } // The shelf will be hidden when dozing with a custom clock, we must show notification // icons in this occasion. if (mStatusBarStateController.isDozing() && mStatusBarComponent.getPanelController().hasCustomClock()) { state |= DISABLE_CLOCK | DISABLE_SYSTEM_INFO; } return state; }关于CollapsedStatusBarFragment 在读到CollapsedStatusBarFragment相关代码的时候, 一时没办法把Fragment与SystemUI串联起来, 这源于传统Fragment的使用习惯: 在Activity中, 获取一个FragmentManager, 创建各种Fragment, 调用replace, show, hide… 难道SystemUI也吃这一套? 状态栏和导航栏不一直是通过WindowManager.addView()直接往里面丢的么! CollapsedStatusBarFragment 本身没什么特别的, 它只是一个android.app.Fragment, 没有特殊的地方, 特殊的是FragmentController, 它与传统的Fragment使用方法完全不同, 参考 frameworks/base/packages/SystemUI/src/com/android/systemui/fragments/FragmentHostManager.java编写一段测试代码, 以便更直观了解它的用法:public class TestActivity extends Activity{ void testFragmentController(Context ctx, Handler h, int winAnim){ if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) { FragmentController fragCtrl = FragmentController.createController(new FragmentHostCallback<Object>(ctx, h, 0) { @Override public Object onGetHost() { return null; } @Override public <T extends View> T onFindViewById(int id) { return findViewById(id); } }); //java.lang.IllegalStateException: Activity has been destroyed // at android.app.FragmentManagerImpl.enqueueAction(FragmentManager.java:1913) fragCtrl.attachHost(null); fragCtrl.dispatchCreate(); fragCtrl.dispatchStart(); fragCtrl.dispatchResume(); //java.lang.IllegalArgumentException: No view found for id 0x7f08007c (com.android.factorytest:id/flRoot) for fragment SimpleFragment{2b5da47 #0 id=0x7f08007c} fragCtrl.getFragmentManager() .beginTransaction() .replace(R.id.flRoot, new SimpleFragment()) .commit(); } } public static class SimpleFragment extends Fragment{ @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { TextView tv = new TextView(getActivity()); tv.setLayoutParams(new ViewGroup.LayoutParams(UiTools.MATCH_PARENT, UiTools.MATCH_PARENT)); tv.setText("FragmentController"); tv.setTextSize(36); return tv; } } }重点关注代码中的createController和FragmentHostCallback, 当创建完成后, 便可以通过 FragmentController的getFragmentManager获取FragmentManager, 接下来就是熟悉的操作, 不多描述.下拉通知黑色背景 在下拉通知面板的过程中, 存在两部分的半透明背景, 第一部分(上)比较明显, 第二部分比较隐藏晦.效果如下图:这是一个自定义的View, 从layout文件中可以找到它: ScrimViewframeworks/base/packages/SystemUI/res/layout/super_notification_shade.xml<com.android.systemui.statusbar.phone.NotificationShadeWindowView xmlns:android="http://schemas.android.com/apk/res/android" xmlns:sysui="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="match_parent" android:fitsSystemWindows="true"> <!-- 省略代码 --> <com.android.systemui.statusbar.ScrimView android:id="@+id/scrim_behind" android:layout_width="match_parent" android:layout_height="match_parent" android:importantForAccessibility="no" sysui:ignoreRightInset="true" />frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/ScrimView.javadiff --git a/frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/ScrimView.java b/frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/ScrimView.java index 7f30009cda..907d58c267 100644 --- a/frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/ScrimView.java +++ b/frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/ScrimView.java @@ -69,7 +69,7 @@ public class ScrimView extends View { @Override protected void onDraw(Canvas canvas) { - if (mDrawable.getAlpha() > 0) { + if (false && mDrawable.getAlpha() > 0) {//强制不进行绘制, 就不会出现半透明背景 mDrawable.draw(canvas); } }第二部分只有在下拉到底部时才会出现(不仔细分辨很难看出来):同样, 来自另一个自定义控件:AlphaOptimizedViewframeworks\base\packages\SystemUI\res\layout\status_bar_expanded.xml<com.android.systemui.statusbar.AlphaOptimizedView android:id="@+id/qs_navbar_scrim" android:layout_height="66dp" android:layout_width="match_parent" android:layout_gravity="bottom" android:visibility="invisible" android:background="@drawable/qs_navbar_scrim" />扩展Dagger, 绕得脑壳疼, 记录下out下的路径out/soong/.intermediates/frameworks/base/packages/SystemUI/SystemUI-core/android_common/kapt/gen/sources/com/android/systemui/dagger/DaggerSystemUIRootComponent.javapublic final class DaggerSystemUIRootComponent implements SystemUIRootComponent { private Provider<SystemUIRootComponent> systemUIRootComponentProvider; this.systemUIRootComponentProvider = InstanceFactory.create((SystemUIRootComponent) this); private Provider<FragmentService> fragmentServiceProvider; this.fragmentServiceProvider = DoubleCheck.provider( FragmentService_Factory.create( systemUIRootComponentProvider, provideConfigurationControllerProvider)); }frameworks/base/packages/SystemUI/src/com/android/systemui/SystemUIAppComponentFactory.java@NonNull @Override public Application instantiateApplicationCompat( @NonNull ClassLoader cl, @NonNull String className) throws InstantiationException, IllegalAccessException, ClassNotFoundException { Application app = super.instantiateApplicationCompat(cl, className); if (app instanceof ContextInitializer) { ((ContextInitializer) app).setContextAvailableCallback( context -> { SystemUIFactory.createFromConfig(context); SystemUIFactory.getInstance().getRootComponent().inject( SystemUIAppComponentFactory.this); } ); } return app; }frameworks/base/packages/SystemUI/src/com/android/systemui/SystemUIFactory.javaprivate void init(Context context) { mRootComponent = buildSystemUIRootComponent(context); // Every other part of our codebase currently relies on Dependency, so we // really need to ensure the Dependency gets initialized early on. Dependency dependency = new Dependency(); mRootComponent.createDependency().createSystemUI(dependency); dependency.start(); } public static void createFromConfig(Context context) { if (mFactory != null) { return; } final String clsName = context.getString(R.string.config_systemUIFactoryComponent); if (clsName == null || clsName.length() == 0) { throw new RuntimeException("No SystemUIFactory component configured"); } try { Class<?> cls = null; cls = context.getClassLoader().loadClass(clsName); mFactory = (SystemUIFactory) cls.newInstance(); mFactory.init(context); } catch (Throwable t) { Log.w(TAG, "Error creating SystemUIFactory component: " + clsName, t); throw new RuntimeException(t); } }frameworks/base/packages/SystemUI/src/com/android/systemui/Dependency.java@Inject Lazy<FragmentService> mFragmentService; protected void start() { mProviders.put(FragmentService.class, mFragmentService::get); }frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.javaFragmentHostManager.get(mPhoneStatusBarWindow)frameworks/base/packages/SystemUI/src/com/android/systemui/fragments/FragmentHostManager.javapublic static FragmentHostManager get(View view) { try { return Dependency.get(FragmentService.class).getFragmentHostManager(view); } catch (ClassCastException e) { // TODO: Some auto handling here? throw e; } }frameworks/base/packages/SystemUI/src/com/android/systemui/fragments/FragmentService.javapublic FragmentHostManager getFragmentHostManager(View view) { View root = view.getRootView(); FragmentHostState state = mHosts.get(root); if (state == null) { state = new FragmentHostState(root); mHosts.put(root, state); } return state.getFragmentHostManager(); }参考SystemUI源码分析之PhoneStatusBar初始化布局简单分析Android SystemUI 状态栏网络图标显示分析(Android 11)SystemUI之状态图标控制Android 8.0 SystemUI(三):一说顶部 StatusBarAndroid 8.0 SystemUI(四):二说顶部 StatusBarDagger 基础知识在 Android 应用中使用 Dagger
概述 自 Android 5.0 版本,Android 带来了沉浸式系统 bar(状态栏和导航栏),Android 的视觉效果进一步提高,各大 app 厂商也在大多数场景上使用沉浸式效果。6.0开始提供了View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR标志位,将状态栏设置为浅色模式, 清除掉这个标志, 可以恢复为深色模式.引自:Android M如何设置状态栏图标黑白色App调用方法主题设置加入, 暗灰图标<item name="android:windowLightStatusBar">true</item>代码中实现切换public static void changeStatusBarContrastStyle(Window window, Boolean lightIcons) { View decorView = window.getDecorView(); if (lightIcons) { // Draw light icons on a dark background color decorView.setSystemUiVisibility(decorView.getSystemUiVisibility() & ~View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR); } else { // Draw dark icons on a light background color decorView.setSystemUiVisibility(decorView.getSystemUiVisibility() | View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR); } }需要更高SDK支持://icon color -> black activity.getWindow().getDecorView().getWindowInsetsController().setSystemBarsAppearance(APPEARANCE_LIGHT_STATUS_BARS, APPEARANCE_LIGHT_STATUS_BARS); //icon color -> white activity.getWindow().getDecorView().getWindowInsetsController().setSystemBarsAppearance(0, APPEARANCE_LIGHT_STATUS_BARS);色调变化流程frameworks/base/core/java/android/view/View.java@Deprecated public void setSystemUiVisibility(int visibility) { if (visibility != mSystemUiVisibility) { mSystemUiVisibility = visibility; if (mParent != null && mAttachInfo != null && !mAttachInfo.mRecomputeGlobalAttributes) { mParent.recomputeViewAttributes(this); } } }frameworks/base/core/java/android/view/ViewRootImpl.java@Override public void recomputeViewAttributes(View child) { checkThread(); if (mView == child) { mAttachInfo.mRecomputeGlobalAttributes = true; if (!mWillDrawSoon) { scheduleTraversals(); } } }frameworks/base/services/core/java/com/android/server/wm/DisplayPolicy.javaint updateSystemUiVisibilityLw() { //...Ignore.... mHandler.post(() -> { StatusBarManagerInternal statusBar = getStatusBarManagerInternal(); if (statusBar != null) { final int displayId = getDisplayId(); statusBar.setDisableFlags(displayId, visibility & StatusBarManager.DISABLE_MASK, cause); if (transientState.first.length > 0) { statusBar.showTransient(displayId, transientState.first); } if (transientState.second.length > 0) { statusBar.abortTransient(displayId, transientState.second); } statusBar.onSystemBarAppearanceChanged(displayId, appearance, appearanceRegions, isNavbarColorManagedByIme); statusBar.topAppWindowChanged(displayId, isFullscreen, isImmersive); // TODO(b/118118435): Remove this after removing system UI visibilities. synchronized (mLock) { mDisplayContent.statusBarVisibilityChanged( visibility & ~(View.STATUS_BAR_UNHIDE | View.NAVIGATION_BAR_UNHIDE)); } } }); return diff; }SystemUI中的流程简单梳理下:参考Android statusbar icons color[ANDROID] 狀態欄(STATUS BAR)文字與圖示轉換成灰色Android 系统 Bar 沉浸式完美兼容方案全屏、沉浸式、fitSystemWindow使用及原理分析:全方位控制“沉浸式”的实现
前言 前面的有写过Android 使用Linphone SDK开发SIP客户端相关的文章, 在后续的开发过程中, 为了更深入了解linphone, 便尝试下载SDK源码自行编译. 关于linphone这里不作过多介绍, 可以参考前面的文章. Linphone-SDK 是一个将 Liblinphone 及其依赖项捆绑为 git 子模块的项目,目的是简化整个 Liblinphone 套件的编译和打包,包括 Mediastreamer2、Belle-sip、oRTP 等。 它的编译生成一个 SDK,适合创建在这些组件之上运行的应用程序。非 Linphone 团队开发或维护的子模块分组在 external/ 目录中。 当前支持的平台有 Android、iOS、Desktop(Linux、Windows、Mac OS X)和 UWP(Universal Windows Platform)。clone 代码GitLab linphone-sdkgit clone https://gitlab.linphone.org/BC/public/linphone-sdk.git注意: 为什么不使用GitHub上的仓库# ******** # **注意** # ******** #从GitHub上克隆下来的代码, 不能正常编译, 原因是有些模块找不到, 更新/下载不来. https://github.com/BelledonneCommunications/linphone-sdk git clone https://github.com/BelledonneCommunications/linphone-sdk.git源码下载[2GB]提取码: 4x4c环境及信赖系统: Ubuntu 20.04内存: 16GB存储: 512GB工具包:Cmake >= 3.11python >= 3.6pip (or pip3 if the build machine has both python2 and python3)yasmnasmdoxygenPystache (use pip install pystache or pip3 install pystache)six (use pip install six or pip3 install six)编译克隆下来解压出来后, 依赖的库代码基本为空, 通过下面的命令, 可以检索出所需要库代码.检索依赖项Linphone-SDK 的 git 存储库包含 git 子模块。 它必须使用 --recursive 选项进行克隆。 更新或切换分支后,永远不要忘记检查和更新子模块:git submodule update --init --recursive这个过程需要较长的时间, 具体看网络条件, 若出现失败建议检查下网络原因, 另外考虑下是否外网访问的问题.完成后, 目录文件 列表:linphone-sdk$ ll total 248 drwxrwxr-x 35 android android 4096 12月 16 15:57 ./ drwxrwxr-x 21 android android 4096 12月 16 09:22 ../ drwxrwxr-x 6 android android 4096 12月 15 20:09 bcg729/ drwxrwxr-x 10 android android 4096 12月 15 20:09 bcmatroska2/ drwxrwxr-x 8 android android 4096 12月 15 20:09 bctoolbox/ drwxrwxr-x 11 android android 4096 12月 15 20:09 bcunit/ drwxrwxr-x 9 android android 4096 12月 15 20:09 belcard/ drwxrwxr-x 9 android android 4096 12月 15 20:09 belle-sip/ drwxrwxr-x 9 android android 4096 12月 15 20:09 belr/ drwxrwxr-x 7 android android 4096 12月 15 20:09 bzrtp/ -rw-rw-r-- 1 android android 2069 12月 15 19:45 CHANGELOG.md drwxrwxr-x 8 android android 4096 12月 16 11:00 cmake/ drwxrwxr-x 10 android android 4096 12月 15 20:09 cmake-builder/ -rw-rw-r-- 1 android android 5602 12月 15 19:45 CMakeLists.txt drwxrwxr-x 2 android android 4096 12月 15 19:45 docker-files/ -rw-rw-r-- 1 android android 10 12月 15 19:45 .envrc drwxrwxr-x 26 android android 4096 12月 15 19:45 external/ -rw-rw-r-- 1 android android 7121 12月 15 19:45 flake.lock -rw-rw-r-- 1 android android 4274 12月 15 19:45 flake.nix drwxrwxr-x 9 android android 4096 12月 15 19:46 .git/ drwxrwxr-x 3 android android 4096 12月 15 19:45 .github/ -rw-rw-r-- 1 android android 302 12月 15 19:45 .gitignore drwxrwxr-x 9 android android 4096 12月 15 19:45 .gitlab-ci-files/ -rw-rw-r-- 1 android android 1598 12月 15 19:45 .gitlab-ci-tunnel.yml -rw-rw-r-- 1 android android 3439 12月 15 19:45 .gitlab-ci.yml -rw-rw-r-- 1 android android 4552 12月 15 19:45 .gitmodules drwxrwxr-x 17 android android 4096 12月 15 20:09 liblinphone/ -rw-rw-r-- 1 android android 34523 12月 15 19:45 LICENSE.txt drwxrwxr-x 9 android android 4096 12月 15 20:09 lime/ drwxrwxr-x 14 android android 4096 12月 15 20:09 mediastreamer2/ drwxrwxr-x 3 android android 4096 12月 15 20:09 msaaudio/ drwxrwxr-x 6 android android 4096 12月 15 20:09 msamr/ drwxrwxr-x 2 android android 4096 12月 15 20:09 msandroidcamera2/ drwxrwxr-x 3 android android 4096 12月 15 20:09 mscodec2/ drwxrwxr-x 4 android android 4096 12月 15 20:09 msoboe/ drwxrwxr-x 5 android android 4096 12月 15 20:09 msopenh264/ drwxrwxr-x 5 android android 4096 12月 15 20:09 mssilk/ drwxrwxr-x 3 android android 4096 12月 15 20:09 mswasapi/ drwxrwxr-x 4 android android 4096 12月 15 20:09 mswebrtc/ drwxrwxr-x 4 android android 4096 12月 15 20:10 mswinrtvid/ drwxrwxr-x 10 android android 4096 12月 15 20:10 ortp/ drwxrwxr-x 7 android android 4096 12月 15 20:10 postquantumcryptoengine/ -rw-rw-r-- 1 android android 13876 12月 15 19:45 README.md drwxrwxr-x 5 android android 4096 12月 15 19:45 tester/开始编译:# 设置Android SDK 路径 linphone-sdk$ export ANDROID_SDK_ROOT=/home/android/Android/Sdk # 设置Android NDK 路径 linphone-sdk$ export PATH=$PATH:/home/android/Android/Sdk/ndk/20.0.5594570 linphone-sdk$ mkdir build linphone-sdk$ cd build # 参考官方 linphone-sdk/build$ cmake .. -DLINPHONESDK_PLATFORM=Android -DLINPHONESDK_ANDROID_ARCHS=arm64,x86,armv7 -DENABLE_SILK=YES -DENABLE_G729==YES # 开始编译 linphone-sdk/build$ cmake --build . -j4编译时间比较长, 耐心等待即可.-DLINPHONESDK_ANDROID_ARCHS的值, 可以参考:arm -> armeabi 已不受支持:CMake Error at /home/android/Android/Sdk/ndk/20.0.5594570/build/cmake/android.toolchain.cmake:177 (message): armeabi is no longer supported. Use armeabi-v7a.linphone-sdk/cmake/Android/CopyLibs.cmake编译完成linphone-sdk/build$ ll linphone-sdk/bin/outputs/aar/ total 198508 drwxrwxr-x 2 android android 4096 12月 17 09:50 ./ drwxrwxr-x 4 android android 4096 12月 17 09:49 ../ -rw-rw-r-- 1 android android 167525201 12月 17 09:50 linphone-sdk-android-debug.aar -rw-rw-r-- 1 android android 35736951 12月 17 09:49 linphone-sdk-android-release.aar生成的linphone-sdk-android-release.aar, 便可以导入给APP开发用.导入后, 出现找不到libc++_shared.soCaused by: java.lang.UnsatisfiedLinkError: dalvik.system.PathClassLoader[DexPathList[[zip file "/data/app/com.saike.ocs-cdHJzDKRk6PW1v0eDsFENQ==/base.apk"],nativeLibraryDirectories=[/data/app/com.saike.ocs-cdHJzDKRk6PW1v0eDsFENQ==/lib/arm, /data/app/com.saike.ocs-cdHJzDKRk6PW1v0eDsFENQ==/base.apk!/lib/armeabi-v7a, /system/lib, /vendor/lib]]] couldn't find "libc++_shared.so" at java.lang.Runtime.loadLibrary0(Runtime.java:1011) at java.lang.System.loadLibrary(System.java:1657) at org.linphone.core.FactoryImpl.<clinit>(Factory.java:727) at org.linphone.core.Factory.instance(Factory.java:49) at com.saike.ocs.phone.SipPhone.loadSipLibs(SipPhone.java:51) at com.saike.ocs.phone.PhoneManager$1.run(PhoneManager.java:60)照着改, 增加一行即可+ file(COPY "${CMAKE_ANDROID_NDK}/sources/cxx-stl/llvm-libc++/libs/${_libarch}/libc++_shared.so" DESTINATION "linphone-sdk/android-${_arch}/lib/")参考linphone-sdk集成第三so之dlopen failed: library “libc++_shared.so” not foundFixed missing libc++_shared.so that happens sometimes
概述Android 11 的状态栏与导航栏较之前的版本有较大的差异, 在Android 7.0 SystemUI 状态/导航栏的隐藏与显示中所描述的部分内容已不再适用.比如, 自动隐藏的时间, 隐藏的动画, 较之前的版本已面目全非, 本文将对隐藏状态栏部分的内容进行一些补充.APP如何隐藏状态栏参考文档:隐藏状态栏_Android 开发者_Android Developers.pdf)方法一:<application ... android:theme="@android:style/Theme.Holo.NoActionBar.Fullscreen" > ... </application>方法二: public class MainActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // If the Android version is lower than Jellybean, use this call to hide // the status bar. if (Build.VERSION.SDK_INT < 16) { getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN); } setContentView(R.layout.activity_main); } ... }方法三:(在4.1(SDK 16)及之上)View decorView = getWindow().getDecorView(); // Hide the status bar. int uiOptions = View.SYSTEM_UI_FLAG_FULLSCREEN; decorView.setSystemUiVisibility(uiOptions); // Remember that you should never show the action bar if the // status bar is hidden, so hide that too if necessary. ActionBar actionBar = getActionBar(); actionBar.hide();状态栏是怎么被隐藏的1. 通过上面的方式主动调用接口设置窗口属性, 由系统判断并完成隐藏frameworks/base/core/java/android/view/InsetsController.java@Override public void onReady(WindowInsetsAnimationController controller, int types) { mController = controller; if (DEBUG) Log.d(TAG, "default animation onReady types: " + types); if (mDisable) { onAnimationFinish(); return; } mAnimator = ValueAnimator.ofFloat(0f, 1f); mAnimator.setDuration(mDurationMs); mAnimator.setInterpolator(new LinearInterpolator()); Insets hiddenInsets = controller.getHiddenStateInsets(); // IME with zero insets is a special case: it will animate-in from offscreen and end // with final insets of zero and vice-versa. hiddenInsets = controller.hasZeroInsetsIme() ? Insets.of(hiddenInsets.left, hiddenInsets.top, hiddenInsets.right, mFloatingImeBottomInset) : hiddenInsets; Insets start = mShow ? hiddenInsets : controller.getShownStateInsets(); Insets end = mShow ? controller.getShownStateInsets() : hiddenInsets; Interpolator insetsInterpolator = getInterpolator(); Interpolator alphaInterpolator = getAlphaInterpolator(); mAnimator.addUpdateListener(animation -> { float rawFraction = animation.getAnimatedFraction(); float alphaFraction = mShow ? rawFraction : 1 - rawFraction; float insetsFraction = insetsInterpolator.getInterpolation(rawFraction); controller.setInsetsAndAlpha( sEvaluator.evaluate(insetsFraction, start, end), alphaInterpolator.getInterpolation(alphaFraction), rawFraction); if (DEBUG) Log.d(TAG, "Default animation setInsetsAndAlpha fraction: " + insetsFraction); }); mAnimator.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { onAnimationFinish(); } }); if (!mHasAnimationCallbacks) { mAnimator.setAnimationHandler(mSfAnimationHandlerThreadLocal.get()); } mAnimator.start(); }为定位到这一段代码, 走了相当曲折又漫长的路.第一个误区: 参照之前的状态栏隐藏流程代码, 在frameworks/base/service中转了很长时间.第二个误区: 误判隐藏动画的是在SystemUI中实现.在不断地调试分析后, 最终的突破口在SurfaceControl的子类Transaction最终输出以下LOG, 最终定位到上面的代码.2022-12-09 17:56:47.413 at android.view.SurfaceControl$SurfaceControl.setPosition(SurfaceControl.java:2435) 2022-12-09 17:56:47.413 at android.view.SurfaceControl$Transaction.setMatrix(SurfaceControl.java:2609) 2022-12-09 17:56:47.413 at android.view.SyncRtSurfaceTransactionApplier.applyParams(SyncRtSurfaceTransactionApplier.java:97) 2022-12-09 17:56:47.413 at com.android.server.wm.InsetsPolicy$InsetsPolicyAnimationControlListener$InsetsPolicyAnimationControlCallbacks.applySurfaceParams(InsetsPolicy.java:542) 2022-12-09 17:56:47.413 at android.view.InsetsAnimationControlImpl.applyChangeInsets(InsetsAnimationControlImpl.java:214) 2022-12-09 17:56:47.413 at com.android.server.wm.InsetsPolicy$InsetsPolicyAnimationControlListener$InsetsPolicyAnimationControlCallbacks.scheduleApplyChangeInsets(InsetsPolicy.java:510) 2022-12-09 17:56:47.413 at android.view.InsetsAnimationControlImpl.setInsetsAndAlpha(InsetsAnimationControlImpl.java:186) 2022-12-09 17:56:47.413 at android.view.InsetsAnimationControlImpl.setInsetsAndAlpha(InsetsAnimationControlImpl.java:170) 2022-12-09 17:56:47.414 at android.view.InsetsController$InternalAnimationControlListener.lambda$onReady$0$InsetsController$InternalAnimationControlListener(InsetsController.java:332) 2022-12-09 17:56:47.414 at android.view.-$$Lambda$InsetsController$InternalAnimationControlListener$SInf91MjJKDQFXwrp7C-HBi0xaQ.onAnimationUpdate(Unknown Source:13) 2022-12-09 17:56:47.414 at android.animation.ValueAnimator.animateValue(ValueAnimator.java:1566) 2022-12-09 17:56:47.414 at android.animation.ValueAnimator.animateBasedOnTime(ValueAnimator.java:1357) 2022-12-09 17:56:47.414 at android.animation.ValueAnimator.doAnimationFrame(ValueAnimator.java:1489) 2022-12-09 17:56:47.414 at android.animation.AnimationHandler.doAnimationFrame(AnimationHandler.java:146) 2022-12-09 17:56:47.414 at android.animation.AnimationHandler.access$100(AnimationHandler.java:37) 2022-12-09 17:56:47.414 at android.animation.AnimationHandler$1.doFrame(AnimationHandler.java:54) 2022-12-09 17:56:47.415 at android.view.Choreographer$CallbackRecord.run(Choreographer.java:970) 2022-12-09 17:56:47.415 at android.view.Choreographer.doCallbacks(Choreographer.java:796) 2022-12-09 17:56:47.415 at android.view.Choreographer.doFrame(Choreographer.java:727) 2022-12-09 17:56:47.415 at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:957) 2022-12-09 17:56:47.415 at android.os.Handler.handleCallback(Handler.java:938) 2022-12-09 17:56:47.415 at android.os.Handler.dispatchMessage(Handler.java:99) 2022-12-09 17:56:47.415 at android.os.Looper.loop(Looper.java:223) 2022-12-09 17:56:47.415 at android.os.HandlerThread.run(HandlerThread.java:67) 2022-12-09 17:56:47.415 at com.android.server.ServiceThread.run(ServiceThread.java:44)状态栏/导航栏 隐藏与显示动画过渡时长:在定位到代码后, 最先做的事情, 就是把时间增加10倍, 编译看效果.frameworks/base/core/java/android/view/InsetsController.javaprivate static final int ANIMATION_DURATION_SHOW_MS = 275; private static final int ANIMATION_DURATION_HIDE_MS = 340;2. 隐藏后, 用户下拉状态栏, SystemUI定时执行自动隐藏(AutoHideController)frameworks/base/services/core/java/com/android/server/wm/InsetsPolicy.javavoid hideTransient() { if (mShowingTransientTypes.size() == 0) { return; } InsetsState state = new InsetsState(mStateController.getRawInsetsState()); startAnimation(false /* show */, () -> { synchronized (mDisplayContent.mWmService.mGlobalLock) { mShowingTransientTypes.clear(); mStateController.notifyInsetsChanged(); updateBarControlTarget(mFocusedWin); } }, state); mStateController.onInsetsModified(mDummyControlTarget, state); } void startAnimation(boolean show, Runnable callback, InsetsState state) { int typesReady = 0; final SparseArray<InsetsSourceControl> controls = new SparseArray<>(); final IntArray showingTransientTypes = mShowingTransientTypes; for (int i = showingTransientTypes.size() - 1; i >= 0; i--) { int type = showingTransientTypes.get(i); InsetsSourceProvider provider = mStateController.getSourceProvider(type); InsetsSourceControl control = provider.getControl(mDummyControlTarget); if (control == null || control.getLeash() == null) { continue; } typesReady |= InsetsState.toPublicType(type); controls.put(control.getType(), new InsetsSourceControl(control)); state.setSourceVisible(type, show); } controlAnimationUnchecked(typesReady, controls, show, callback); } private void controlAnimationUnchecked(int typesReady, SparseArray<InsetsSourceControl> controls, boolean show, Runnable callback) { InsetsPolicyAnimationControlListener listener = new InsetsPolicyAnimationControlListener(show, callback, typesReady); listener.mControlCallbacks.controlAnimationUnchecked(typesReady, controls, show); } private class InsetsPolicyAnimationControlListener extends InsetsController.InternalAnimationControlListener { Runnable mFinishCallback; InsetsPolicyAnimationControlCallbacks mControlCallbacks; InsetsPolicyAnimationControlListener(boolean show, Runnable finishCallback, int types) { super(show, false /* hasCallbacks */, types, false /* disable */, (int) (mDisplayContent.getDisplayMetrics().density * FLOATING_IME_BOTTOM_INSET + 0.5f)); mFinishCallback = finishCallback; mControlCallbacks = new InsetsPolicyAnimationControlCallbacks(this); } private class InsetsPolicyAnimationControlCallbacks implements InsetsAnimationControlCallbacks { ... private void controlAnimationUnchecked(int typesReady, SparseArray<InsetsSourceControl> controls, boolean show) { if (typesReady == 0) { // nothing to animate. return; } mAnimatingShown = show; mAnimationControl = new InsetsAnimationControlImpl(controls, mFocusedWin.getDisplayContent().getBounds(), getState(), mListener, typesReady, this, mListener.getDurationMs(), InsetsController.SYSTEM_BARS_INTERPOLATOR, show ? ANIMATION_TYPE_SHOW : ANIMATION_TYPE_HIDE); SurfaceAnimationThread.getHandler().post( () -> mListener.onReady(mAnimationControl, typesReady)); }一些类图一些关键代码.frameworks/base/core/java/android/view/ViewRootImpl.javacase MSG_SHOW_INSETS: { if (mView == null) { Log.e(TAG, String.format("Calling showInsets(%d,%b) on window that no longer" + " has views.", msg.arg1, msg.arg2 == 1)); } clearLowProfileModeIfNeeded(msg.arg1, msg.arg2 == 1); mInsetsController.show(msg.arg1, msg.arg2 == 1); break; }private void controlInsetsForCompatibility(WindowManager.LayoutParams params) { if (sNewInsetsMode != NEW_INSETS_MODE_FULL) { return; } final int sysUiVis = params.systemUiVisibility | params.subtreeSystemUiVisibility; final int flags = params.flags; final boolean matchParent = params.width == MATCH_PARENT && params.height == MATCH_PARENT; final boolean nonAttachedAppWindow = params.type >= FIRST_APPLICATION_WINDOW && params.type <= LAST_APPLICATION_WINDOW; final boolean statusWasHiddenByFlags = (mTypesHiddenByFlags & Type.statusBars()) != 0; final boolean statusIsHiddenByFlags = (sysUiVis & SYSTEM_UI_FLAG_FULLSCREEN) != 0 || ((flags & FLAG_FULLSCREEN) != 0 && matchParent && nonAttachedAppWindow); final boolean navWasHiddenByFlags = (mTypesHiddenByFlags & Type.navigationBars()) != 0; final boolean navIsHiddenByFlags = (sysUiVis & SYSTEM_UI_FLAG_HIDE_NAVIGATION) != 0; @InsetsType int typesToHide = 0; @InsetsType int typesToShow = 0; if (statusIsHiddenByFlags && !statusWasHiddenByFlags) { typesToHide |= Type.statusBars(); } else if (!statusIsHiddenByFlags && statusWasHiddenByFlags) { typesToShow |= Type.statusBars(); } if (navIsHiddenByFlags && !navWasHiddenByFlags) { typesToHide |= Type.navigationBars(); } else if (!navIsHiddenByFlags && navWasHiddenByFlags) { typesToShow |= Type.navigationBars(); } if (typesToHide != 0) { getInsetsController().hide(typesToHide); } if (typesToShow != 0) { getInsetsController().show(typesToShow); } mTypesHiddenByFlags |= typesToHide; mTypesHiddenByFlags &= ~typesToShow; }参考隐藏状态栏| Android 开发者Android 显示、隐藏状态栏和导航栏SurfaceFlinger中Layer的修改 - 安卓R
概述 WebRTC名称源自网页实时通信(Web Real-Time Communication)的缩写,是一个支持网页浏览器进行实时语音对话或视频对话的技术,是谷歌2010年以6820万美元收购Global IP Solutions公司而获得的一项技术。Google于2011年6月3日开源的即时通讯项目,旨在使其成为客户端视频通话的标准。其实在Google将WebRTC开源之前,微软和苹果各自的通讯产品已占用很大市场份额(如Skype),Google也是为了快速扩大市场,所以将他给开源。在行业内得到了广泛的支持和应用,成为下一代视频通话的标准。更多介绍可以去官网上看。 WebRTC被誉为是web长期开源开发的一个新启元,是近年来Web开发的最重要创新。WebRTC允许Web开发者在其web应用中添加视频聊天或者点对点数据传输,不需要复杂的代码或者昂贵的配置。目前支持Chrome、Firefox和Opera,后续会支持更多的浏览器,它有能力达到数十亿的设备。 目前,WebRTC的应用已经不局限在浏览器与浏览器之间,通过官方提供的SDK,我们可以很容易的实现本地应用间的音视频传输。在Android平台上,我们也非常容易的集成WebRTC框架,用非常简洁的代码就能实现强大、可靠的音视频传输功能。实现说明本文代码修改自meshenger-androidTrue P2P Voice- and video phone calls without the need for accounts or access to the Internet. There is no discovery mechanism, no meshing and no servers. Just scan each others QR-Code that will contain the contacts IP address. This works in many local networks such as community mesh networks, company networks or at home.翻译如下:真正的 P2P 语音和视频电话呼叫,无需帐户或访问互联网。 没有发现机制,没有网格化,也没有服务器。 只需相互扫描包含联系人 IP 地址的二维码即可。 这适用于许多本地网络,例如社区网状网络、公司网络或家庭网络。版本: meshenger-android-3.0.3 最后的JAVA版本, 最新版本已经改用kotlin基本情况: 功能满足一个局域网P2P的视频通话功能二维码身份生成-----正常二维码扫码添加通讯录-----正常连接发起通话------异常主要问题在于无法创建两端之间的Socket连接, 与WebRTC本身无关通讯加解密 ----- 异常视频通话 ---- 只显示对方视频不显示自身感谢作者1.增加WebRtc支持build.gradledependencies { implementation 'org.webrtc:google-webrtc:1.0.32006' }2.关键代码及应用创建 PeerConnectionFactoryprivate void initRTC() { log("initRTC"); eglCtxRemote = EglBase.create().getEglBaseContext(); eglCtxLocal = EglBase.create().getEglBaseContext(); //创建 PeerConnectionFactory //这种方法存在兼容性问题, 在一些平台上, 会导致后续流程不能正常执行. /*PeerConnectionFactory.initialize(PeerConnectionFactory .InitializationOptions.builder(context) .createInitializationOptions()); factory = PeerConnectionFactory.builder().createPeerConnectionFactory();*/ constraints = new MediaConstraints(); constraints.optional.add(new MediaConstraints.KeyValuePair("offerToReceiveAudio", "true")); constraints.optional.add(new MediaConstraints.KeyValuePair("offerToReceiveVideo", "true")); constraints.optional.add(new MediaConstraints.KeyValuePair("DtlsSrtpKeyAgreement", "true")); //initVideoTrack(); PeerConnectionFactory.initialize(PeerConnectionFactory.InitializationOptions.builder(context).createInitializationOptions()); PeerConnectionFactory.Options options = new PeerConnectionFactory.Options(); //https://yuriyshea.com/archives/androidwebrtc%E8%B8%A9%E5%9D%91%E6%8C%87%E5%8D%97 DefaultVideoEncoderFactory enVdf = new DefaultVideoEncoderFactory(eglCtxRemote, true, true); VideoDecoderFactory deVdf = new DefaultVideoDecoderFactory(eglCtxRemote); //创建 PeerConnectionFactory factory = PeerConnectionFactory.builder() .setOptions(options) .setVideoEncoderFactory(enVdf) .setVideoDecoderFactory(deVdf) .createPeerConnectionFactory(); log("initRTC done"); }创建PeerConnection 发起呼叫connection = factory.createPeerConnection(Collections.emptyList(), new DefaultObserver() { @Override public void onIceGatheringChange(PeerConnection.IceGatheringState iceGatheringState) { super.onIceGatheringChange(iceGatheringState); log("Outgoing.onIceGatheringChange " + iceGatheringState.name()); if (iceGatheringState == PeerConnection.IceGatheringState.COMPLETE) { log("Outgoing.connect call from remote address: " + contact.getAddresses()); reportStateChange(CallState.CONNECTING); //发送信息给接收方,告知发起通话. getPublisher().sendCall(contact.getAddresses(), connection.getLocalDescription().description); } @Override public void onIceConnectionChange(PeerConnection.IceConnectionState iceConnectionState) { log("Outgoing.onIceConnectionChange " + iceConnectionState.name()); super.onIceConnectionChange(iceConnectionState); if (iceConnectionState == PeerConnection.IceConnectionState.DISCONNECTED) { reportStateChange(CallState.DISCONNECTED); }else if (iceConnectionState == PeerConnection.IceConnectionState.CLOSED) { hangUp("Outgoing.onIceConnectionChange CLOSED"); } } @Override public void onAddStream(MediaStream mediaStream) { log("Outgoing.onAddStream"); super.onAddStream(mediaStream); handleMediaStream(mediaStream); } @Override public void onDataChannel(DataChannel dataChannel) { log("Outgoing.onDataChannel"); super.onDataChannel(dataChannel); RTCCall.this.dataChannel = dataChannel; dataChannel.registerObserver(RTCCall.this); } }); //初始化音视频通道 connection.addStream(createStream()); //创建数据通道, 可用于收发消息. this.dataChannel = connection.createDataChannel("data", new DataChannel.Init()); this.dataChannel.registerObserver(this); log("Outgoing.createOffer"); connection.createOffer(new DefaultSdpObserver() { @Override public void onCreateSuccess(SessionDescription sessionDescription) { log("Outgoing.onCreateSuccess"); super.onCreateSuccess(sessionDescription); connection.setLocalDescription(new DefaultSdpObserver(), sessionDescription); } }, constraints);呼叫方收到后同样初始化, 并在点击接听后创建PeerConnectionpublic void accept(OnStateChangeListener listener) { log("accept"); this.listener = listener; new Thread(() -> { connection = factory.createPeerConnection(this.iceServers, new DefaultObserver() { @Override public void onIceGatheringChange(PeerConnection.IceGatheringState iceGatheringState) { super.onIceGatheringChange(iceGatheringState); if (iceGatheringState == PeerConnection.IceGatheringState.COMPLETE) { log("Incoming.onIceGatheringChange"); //通知已接听 getPublisher().sendAnswer(contact.getAddresses(), connection.getLocalDescription().description); reportStateChange(CallState.CONNECTED); } } @Override public void onIceConnectionChange(PeerConnection.IceConnectionState iceConnectionState) { log("Incoming.onIceConnectionChange " + iceConnectionState.name()); super.onIceConnectionChange(iceConnectionState); if (iceConnectionState == PeerConnection.IceConnectionState.DISCONNECTED) { reportStateChange(CallState.DISCONNECTED); }else if (iceConnectionState == PeerConnection.IceConnectionState.CLOSED) { hangUp("Incoming.onIceConnectionChange CLOSED"); } } @Override public void onAddStream(MediaStream mediaStream) { log("Incoming.onAddStream"); super.onAddStream(mediaStream); handleMediaStream(mediaStream); } @Override public void onDataChannel(DataChannel dataChannel) { super.onDataChannel(dataChannel); RTCCall.this.dataChannel = dataChannel; dataChannel.registerObserver(RTCCall.this); } }); connection.addStream(createStream()); //this.dataChannel = connection.createDataChannel("data", new DataChannel.Init()); log("Incoming.setting remote description"); //设置会话, 创建响应应答 connection.setRemoteDescription(new DefaultSdpObserver() { @Override public void onSetSuccess() { super.onSetSuccess(); log("creating answer..."); connection.createAnswer(new DefaultSdpObserver() { @Override public void onCreateSuccess(SessionDescription sessionDescription) { log("Incoming.onCreateSuccess"); super.onCreateSuccess(sessionDescription); connection.setLocalDescription(new DefaultSdpObserver(), sessionDescription); } @Override public void onCreateFailure(String s) { super.onCreateFailure(s); log("Incoming.onCreateFailure: " + s); } }, constraints); } }, new SessionDescription(SessionDescription.Type.OFFER, offer)); }).start(); }呼叫方处理应答private void handleAnswer(String remoteDesc) { log("handleAnswer"); connection.setRemoteDescription(new DefaultSdpObserver() { @Override public void onSetSuccess() { super.onSetSuccess(); } @Override public void onSetFailure(String s) { super.onSetFailure(s); } }, new SessionDescription(SessionDescription.Type.ANSWER, remoteDesc)); }启动摄像头public void setVideoEnabled(boolean enabled) { log("setVideoEnabled enabled=" + enabled); this.videoEnabled = enabled; try { if (enabled) { this.capturer.startCapture(640, 480, 30); } else { this.capturer.stopCapture(); } JSONObject object = new JSONObject(); object.put(StateChangeMessage, enabled ? CameraEnabledMessage : CameraDisabledMessage); log("setVideoEnabled: " + object); dataChannel.send(new DataChannel.Buffer(ByteBuffer.wrap(object.toString().getBytes()), false)); } catch (JSONException e) { e.printStackTrace(); } catch (InterruptedException e) { e.printStackTrace(); } }挂断public void hangUp(String res) { if(state == CallState.ENDED){ log("hangUp Ignored already ENDED:" + res); return; } log("hangUp:" + res); reportStateChange(CallState.ENDED); closePeerConnection(); //通知挂断. new Thread(() -> { getPublisher().sendHangup(contact.getAddresses()); }).start(); }//Fatal signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0x0 in tid 13128 (signaling_threa), pid 13067 (d.d.meshenger) //type=1400 audit(0.0:28585): avc: granted { nlmsg_readpriv } for scontext=u:r:untrusted_app_29:s0:c5,c257,c512,c768 tcontext=u:r:untrusted_app_29:s0:c5,c257,c512,c768 tclass=netlink_route_socket app=d.d.meshenger //pid: 13067, tid: 13128, name: signaling_threa >>> d.d.meshenger <<< private void closePeerConnection() { log("closePeerConnection"); if(localRenderer != null){ localRenderer.release(); localRenderer = null; } if(remoteRenderer != null){ remoteRenderer.release(); remoteRenderer = null; } if(capturer != null){ try { capturer.stopCapture(); capturer.dispose(); capturer = null; } catch (InterruptedException e) { e.printStackTrace(); } } if (connection != null) { try { PeerConnection conn = connection; connection = null; conn.close(); } catch (Exception e) { e.printStackTrace(); } //connection = null; log("closePeerConnection done"); } }完整呼叫流程LOG如下[呼叫方]## 开始呼出 2022-12-01 14:50:09.016 23145-23717 RTCCall D RTCCall created 2022-12-01 14:50:09.016 23145-23717 RTCCall D initRTC 2022-12-01 14:50:09.041 23145-23717 RTCCall D initRTC done 2022-12-01 14:50:09.042 23145-23728 RTCCall D createPeerConnection 2022-12-01 14:50:09.052 23145-23728 RTCCall D createStream 2022-12-01 14:50:09.058 23145-23728 RTCCall D createCapturer 2022-12-01 14:50:09.139 23145-23728 RTCCall D Outgoing.createOffer 2022-12-01 14:50:09.144 23145-23725 RTCCall D Outgoing.onCreateSuccess 2022-12-01 14:50:09.212 23145-23725 RTCCall D Outgoing.onIceGatheringChange GATHERING 2022-12-01 14:50:09.327 23145-23725 RTCCall D Outgoing.onIceGatheringChange COMPLETE 2022-12-01 14:50:09.327 23145-23725 RTCCall D transferring offer... 2022-12-01 14:50:09.328 23145-23735 RTCCall D Outgoing.connect call from remote address: 192.168.7.239 2022-12-01 14:50:09.328 23145-23735 RTCCall D reportStateChange CONNECTING ## 对方接听 2022-12-01 14:50:15.331 23145-23168 RTCCall D reportStateChange CONNECTED 2022-12-01 14:50:15.331 23145-23168 RTCCall D handleAnswer 2022-12-01 14:50:15.409 23145-23725 RTCCall D Outgoing.onIceConnectionChange CHECKING 2022-12-01 14:50:15.415 23145-23725 RTCCall D Outgoing.onAddStream 2022-12-01 14:50:15.415 23145-23725 RTCCall D handleMediaStream ava=false 2022-12-01 14:50:15.416 23145-23725 RTCCall D handleAnswer.onSetSuccess 2022-12-01 14:50:15.512 23145-23725 RTCCall D Outgoing.onIceConnectionChange CONNECTED 2022-12-01 14:50:15.528 23145-23725 RTCCall D onStateChange ## 对方开启摄像头, 并推送 2022-12-01 14:50:24.939 23145-23725 RTCCall D onMessage: {"StateChange":"CameraEnabled"} 2022-12-01 14:50:30.932 23145-23725 RTCCall D Outgoing.onIceConnectionChange COMPLETED ## 开启摄像头并推送 2022-12-01 14:50:39.122 23145-23145 RTCCall D setVideoEnabled enabled=true 2022-12-01 14:50:39.122 23145-23145 RTCCall D setVideoEnabled: {"StateChange":"CameraEnabled"} 2022-12-01 14:50:39.124 23145-23725 RTCCall D onBufferedAmountChange l=31 ## 挂断 2022-12-01 14:51:03.363 23145-23145 RTCCall D hangUp:UI.callDecline click 2022-12-01 14:51:03.363 23145-23145 RTCCall D reportStateChange ENDED 2022-12-01 14:51:03.363 23145-23145 RTCCall D closePeerConnection 2022-12-01 14:51:03.370 23145-23145 RTCCall D closePeerConnection state=CONNECTED 2022-12-01 14:51:03.372 23145-23725 RTCCall D Outgoing.onIceConnectionChange CLOSED 2022-12-01 14:51:03.372 23145-23725 RTCCall D hangUp Ignored already ENDED:Outgoing.onIceConnectionChange CLOSED 2022-12-01 14:51:03.547 23145-23725 RTCCall D onStateChange 2022-12-01 14:51:03.547 23145-23725 RTCCall D onStateChange 2022-12-01 14:51:03.580 23145-23145 RTCCall D closePeerConnection done 2022-12-01 14:51:04.059 23145-23145 RTCCall D releaseCamera 2022-12-01 14:51:04.149 23145-23168 RTCCall D hangUp Ignored already ENDED:publisher msg[被叫方]## 来电并响铃 2022-12-01 14:22:30.319 8916-8943 RTCCall D initRTC 2022-12-01 14:22:30.363 8916-8943 RTCCall D initRTC done 2022-12-01 14:22:30.364 8916-8943 RTCCall D reportStateChange RINGING ## 接听 2022-12-01 14:22:35.625 8916-8916 RTCCall D setRenderer 2022-12-01 14:22:35.625 8916-8916 RTCCall D accept 2022-12-01 14:22:35.661 8916-14310 RTCCall D createStream 2022-12-01 14:22:35.662 8916-14310 RTCCall D createCapturer 2022-12-01 14:22:35.677 8916-14310 RTCCall D Incoming.setting remote description 2022-12-01 14:22:35.768 8916-14256 RTCCall D Incoming.onAddStream 2022-12-01 14:22:35.768 8916-14256 RTCCall D handleMediaStream ava=false 2022-12-01 14:22:35.769 8916-14256 RTCCall D creating answer... 2022-12-01 14:22:35.773 8916-14256 RTCCall D Incoming.onCreateSuccess 2022-12-01 14:22:35.873 8916-14256 RTCCall D Incoming.onIceConnectionChange CHECKING 2022-12-01 14:22:36.035 8916-14256 RTCCall D Incoming.onIceGatheringChange ## 连接已建立 2022-12-01 14:22:36.048 8916-14256 RTCCall D reportStateChange CONNECTED 2022-12-01 14:22:36.256 8916-14256 RTCCall D Incoming.onIceConnectionChange CONNECTED 2022-12-01 14:22:36.278 8916-14256 RTCCall D onStateChange ## 开启摄像头并推送 2022-12-01 14:22:45.635 8916-8916 RTCCall D setVideoEnabled enabled=true 2022-12-01 14:22:45.636 8916-8916 RTCCall D setVideoEnabled: {"StateChange":"CameraEnabled"} 2022-12-01 14:22:45.638 8916-14256 RTCCall D onBufferedAmountChange l=31 ## 对方开启摄像头 2022-12-01 14:23:02.916 8916-14256 RTCCall D onMessage: {"StateChange":"CameraEnabled"} ## 对方已挂断 2022-12-01 14:23:24.318 8916-14256 RTCCall D Incoming.onIceConnectionChange DISCONNECTED 2022-12-01 14:23:24.318 8916-14256 RTCCall D reportStateChange DISCONNECTED 2022-12-01 14:23:24.320 8916-14256 RTCCall D onStateChange 2022-12-01 14:23:24.320 8916-14256 RTCCall D onStateChange 2022-12-01 14:23:24.430 8916-8943 RTCCall D hangUp:publisher msg 2022-12-01 14:23:24.430 8916-8943 RTCCall D reportStateChange ENDED 2022-12-01 14:23:24.431 8916-8943 RTCCall D closePeerConnection 2022-12-01 14:23:24.445 8916-8943 RTCCall D closePeerConnection state=CONNECTED 2022-12-01 14:23:24.449 8916-14256 RTCCall D Incoming.onIceConnectionChange CLOSED 2022-12-01 14:23:24.449 8916-14256 RTCCall D hangUp Ignored already ENDED:Incoming.onIceConnectionChange CLOSED 2022-12-01 14:23:24.705 8916-8943 RTCCall D closePeerConnection done 2022-12-01 14:23:24.924 8916-8916 RTCCall D releaseCamera一些问题首先是源码中Socket连接的问题Utils.java 与IPV6有关, 这里改成了IPV4.并在后续的网络相关部分改为使用IP地址.public static List<InetSocketAddress> getAddressPermutations(String contact_mac, int port) { byte[] contact_mac_bytes = Utils.macAddressToBytes(contact_mac); ArrayList<InetSocketAddress> addrs = new ArrayList<InetSocketAddress>(); try { List<NetworkInterface> all = Collections.list(NetworkInterface.getNetworkInterfaces()); for (NetworkInterface nif : all) { if (nif.isLoopback()) { continue; } for (InterfaceAddress ia : nif.getInterfaceAddresses()) { InetAddress addr = ia.getAddress(); if (addr.isLoopbackAddress()) { continue; } android.util.Log.d("Utils", "getAddressPermutations " + addr.getHostName() + "," + addr.getHostAddress() + ","); if (addr instanceof Inet4Address) { addrs.add(new InetSocketAddress(addr, port)); /*Inet6Address addr6 = (Inet6Address) addr; byte[] extracted_mac = getEUI64MAC(addr6); if (extracted_mac != null && Arrays.equals(extracted_mac, nif.getHardwareAddress())) { // We found the interface MAC address in the IPv6 assigned to that interface in the EUI-64 scheme. // Now assume that the contact has an address with the same scheme. InetAddress new_addr = createEUI64Address(addr6, contact_mac_bytes); if (new_addr != null) { addrs.add(new InetSocketAddress(new_addr, port)); } }*/ } } } } catch (Exception e) { e.printStackTrace(); }增加本地摄像头预览显示方法是传入本地的SurfaceViewRenderer并修改getVideoTrackprivate boolean enablePreview = true; private VideoTrack getVideoTrack() { this.capturer = createCapturer(); if(!enablePreview) { return factory.createVideoTrack("video1", factory.createVideoSource(false)); }else { VideoSource videoSource = factory.createVideoSource(false); //EglBase.Context eglBaseContext = EglBase.create().getEglBaseContext(); SurfaceTextureHelper surfaceTextureHelper = SurfaceTextureHelper.create("CaptureThread", eglCtxLocal); capturer.initialize(surfaceTextureHelper, App.getApp(), videoSource.getCapturerObserver()); //capturer.startCapture(480, 640, 30); VideoTrack track = factory.createVideoTrack("video1", videoSource); track.addSink(localRenderer); return track; } }初始化方式问题导致无正常回调constraints = new MediaConstraints(); constraints.optional.add(new MediaConstraints.KeyValuePair("offerToReceiveAudio", "true")); constraints.optional.add(new MediaConstraints.KeyValuePair("offerToReceiveVideo", "true")); constraints.optional.add(new MediaConstraints.KeyValuePair("DtlsSrtpKeyAgreement", "true")); //方式1: PeerConnectionFactory.initialize(PeerConnectionFactory .InitializationOptions.builder(context) .createInitializationOptions()); factory = PeerConnectionFactory.builder().createPeerConnectionFactory(); //方式2: PeerConnectionFactory.initialize(PeerConnectionFactory.InitializationOptions.builder(context).createInitializationOptions()); PeerConnectionFactory.Options options = new PeerConnectionFactory.Options(); DefaultVideoEncoderFactory enVdf = new DefaultVideoEncoderFactory(eglCtxRemote, true, true); VideoDecoderFactory deVdf = new DefaultVideoDecoderFactory(eglCtxRemote); factory = PeerConnectionFactory.builder() .setOptions(options) .setVideoEncoderFactory(enVdf) .setVideoDecoderFactory(deVdf) .createPeerConnectionFactory();方式1 会导致呼出时的错误如下connection.createOffer(new DefaultSdpObserver() { @Override public void onCreateSuccess(SessionDescription sessionDescription) { log("Outgoing.onCreateSuccess"); super.onCreateSuccess(sessionDescription); connection.setLocalDescription(new DefaultSdpObserver(){ @Override public void onSetFailure(String s) { super.onSetFailure(s); //出错时的LOG: //onSetFailure s= //Failed to set local offer sdp: //Failed to set local video description recv parameters for m-section with mid='video'. log("Outgoing.onSetFailure s=" + s); } }, sessionDescription); } }, constraints);多次调用PeerConnection.close()会导致崩溃2022-12-01 14:31:57.847 22887-22887 DEBUG pid-22887 A Build fingerprint: 'google/blueline/blueline:12/SP1A.210812.016.C1/8029091:user/release-keys' 2022-12-01 14:31:57.847 22887-22887 DEBUG pid-22887 A Revision: 'MP1.0' 2022-12-01 14:31:57.847 22887-22887 DEBUG pid-22887 A ABI: 'arm64' 2022-12-01 14:31:57.847 22887-22887 DEBUG pid-22887 A Timestamp: 2022-12-01 14:31:57.642912791+0800 2022-12-01 14:31:57.847 22887-22887 DEBUG pid-22887 A Process uptime: 0s 2022-12-01 14:31:57.847 22887-22887 DEBUG pid-22887 A Cmdline: d.d.meshenger 2022-12-01 14:31:57.847 22887-22887 DEBUG pid-22887 A pid: 22778, tid: 22851, name: signaling_threa >>> d.d.meshenger <<< 2022-12-01 14:31:57.847 22887-22887 DEBUG pid-22887 A uid: 10261 2022-12-01 14:31:57.847 22887-22887 DEBUG pid-22887 A signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0x0 2022-12-01 14:31:57.847 22887-22887 DEBUG pid-22887 A Cause: null pointer dereference 2022-12-01 14:31:57.847 22887-22887 DEBUG pid-22887 A x0 0000000000000000 x1 0000000000000005 x2 0000000000000000 x3 0000007c6f2be89d 2022-12-01 14:31:57.847 22887-22887 DEBUG pid-22887 A x4 0000007c584fd818 x5 0000007f12e7a555 x6 73656d2f642f644c x7 632f7265676e6568 2022-12-01 14:31:57.847 22887-22887 DEBUG pid-22887 A x8 0000007be2f5a000 x9 81248e9b13f44bd4 x10 0000000000430000 x11 0000000000000001 2022-12-01 14:31:57.847 22887-22887 DEBUG pid-22887 A x12 0000000000000004 x13 0000000000000004 x14 7ffbffff00000000 x15 0000000000000000 2022-12-01 14:31:57.847 22887-22887 DEBUG pid-22887 A x16 0000007c584fcf00 x17 0000007f23435688 x18 0000007be1bc6000 x19 0000007d918a0910 2022-12-01 14:31:57.847 22887-22887 DEBUG pid-22887 A x20 0000000000000005 x21 0000007c584fe000 x22 0000007c584fd960 x23 0000007c584fe000 2022-12-01 14:31:57.847 22887-22887 DEBUG pid-22887 A x24 0000007be2f16ab8 x25 00000000ffffffff x26 0000007c584fdff8 x27 00000000000fc000 2022-12-01 14:31:57.847 22887-22887 DEBUG pid-22887 A x28 0000007c58405000 x29 0000007c584fda10 2022-12-01 14:31:57.847 22887-22887 DEBUG pid-22887 A lr 0000007be34be6e0 sp 0000007c584fd950 pc 0000007be34be6f4 pst 0000000060000000资源源码及资料下载Android WebRTC 的一些资料参考WebRTCgooglesource webrtc / src git clone https://webrtc.googlesource.com/src (需要连接外网)meshenger-androidWebRTC-Android 探索 - 创建音视频通话程序的基本姿势WebRTC实现Android传屏demoAndroid WebRTC踩坑指南Google WebRtc Android 使用详解(包括客户端和服务端代码)owt-client-androidandroid webrtc学习 一(源码下载和编译)编译webrtc android源码libwebrtc.aar
平台RK3288 + Linphone 5.1.0 + Android Studio概述 简单来说, 有了解过互联网电话服务或IM(即时消息)功能的.一般都会接触到VOIP和SIP, 实现即时通讯, 发文本消息也好话音通话也好, 甚至于视频通话.关于SIP(Session Initiation Protocol,会话初始协议) VoIP是一个广义术语,可用于描述任何互联网电话服务,从低成本的住宅服务到企业统一通信工具的复杂实现。VoIP是一个可以用来描述任何基于Internet的电话服务的术语,而SIP是一种用于大多数类型VoIP部署的通信协议。 在早期开发android的SIP 客户端的时候, 常常可以看到sipdroid的身影, 在前面的文章中已经有提及过并使用测试过, 只是这个项目目前来看, 只能用于做做DEMO, 简单的测试一些功能, 如注册, 登陆, 发文本消息之类的, 项目的推进/更新也不积极,|-- 尝试过另外两个项目: |–csipsimple: 不好用/不会用 |–abto_sip: 可测试用, 某些平台崩溃,官方付费最终采用了Linphone 自 2001 年作为第一个在 Linux 上使用 SIP 的开源应用程序推出以来,Linphone 已经变得非常流行,尤其是在开源社区中。 我们的工程团队一直致力于 Linphone 项目,以支持最流行平台的最新版本,并提供高级语音/视频和即时消息功能。linphone-android客户端源码linphone-SDK使用Linphone-sdk打造一个SIP客户端Gradle 版本从linphone-SDK下载对应SDK并添加依赖当前使用的版本是 linphone-sdk-android-5.1.0-beta.aarbuild.gradledependencies { implementation files('libs/linphone-sdk-android-5.1.0-beta.aar') }SipPhone.java : 初始化import org.linphone.core.Account; import org.linphone.core.AuthInfo; import org.linphone.core.Call; import org.linphone.core.CallParams; import org.linphone.core.Config; import org.linphone.core.Core; import org.linphone.core.CoreListener; import org.linphone.core.CoreListenerStub; import org.linphone.core.Factory; public class SipPhone extends IPhone { Factory factory; Core core; AuthInfo user; AccountParams accountParams; Call currentCall; //初始化Factory, 在APP启动时调用. public static void loadSipLibs(){ Factory.instance(); } void initSip(Activity activity){ Logger.i(TAG, "initSip"); factory = Factory.instance(); core = factory.createCore(null, null, activity); core.addListener(coreListener); //配置视频通话 core.enableVideoCapture(true); core.enableVideoDisplay(true); core.getVideoActivationPolicy().setAutomaticallyAccept(true); //音频部分, 这里增加了一个遍历, 用于设置指定的音频格式. //h264, no VP8 fixed outgoing call no video. PayloadType[] payloads = core.getVideoPayloadTypes(); for(int i = 0; i < payloads.length; i ++){ //Payload:null, VP8/90000/0, A VP8 video encoder using libvpx library., VP8 //Payload:profile-level-id=42801F, H264/90000/0, A H264 encoder based on MediaCodec API., H264 PayloadType pt = payloads[i]; //判断是否指定的音频格式. boolean goodPayload = PREFER_PAYLOAD.equals(pt.getMimeType()); pt.enable(goodPayload); } //https://github.com/BelledonneCommunications/linphone-android/issues/1153 //https://blog.csdn.net/AdrianAndroid/article/details/70048040 //do not working //H264Helper.setH264Mode(H264Helper.MODE_AUTO, core); //回声消除, 与音频增益. //Logger.d(TAG, "initSip Cancellation=" + core.echoCancellationEnabled()); Logger.d(TAG, "initSip getMicGainDb=" + core.getMicGainDb()); Logger.d(TAG, "initSip PlaybackGainDb=" + core.getPlaybackGainDb()); //core.enableEchoCancellation(true); Logger.d(TAG, "initSip finish Cancellation=" + core.echoCancellationEnabled()); } }SipPhone.java : 登陆void login(){ i("login"); String username = PreferenceUtils.getStringFromDefault(App.getApp(), App.PREF_VOIP_USER, ""); String password = PreferenceUtils.getStringFromDefault(App.getApp(), App.PREF_VOIP_PWD, ""); String domain = PreferenceUtils.getStringFromDefault(App.getApp(), App.PREF_VOIP_IP, ""); String port = PreferenceUtils.getStringFromDefault(App.getApp(), App.PREF_VOIP_PORT, App.DEF_SIP_PORT); if(!StringTools.isNotEmpty(username, password, domain, port)){ e("login failed: username(" + username + "), password(" + password + "), domain(" + domain + "), port(" + port + ")"); return; } //sip:100@192.168.7.119:6060 if(!domain.contains(":")){ domain += ":" + port; } user = factory.createAuthInfo(username, null, password, null, null, domain, null); accountParams = core.createAccountParams(); // A SIP account is identified by an identity address that we can construct from the username and domain String sipAddress = "sip:" + username + "@" + domain; Address identity = factory.createAddress(sipAddress); i("login for address " + sipAddress); accountParams.setIdentityAddress(identity); // We also need to configure where the proxy server is located Address address = factory.createAddress("sip:" + domain); // We use the Address object to easily set the transport protocol address.setTransport(TransportType.Udp); accountParams.setServerAddress(address); // And we ensure the account will start the registration process accountParams.setRegisterEnabled(true); // Asks the CaptureTextureView to resize to match the captured video's size ratio //core.getConfig().setBool("video", "auto_resize_preview_to_keep_ratio", true); // Now that our AccountParams is configured, we can create the Account object Account account = core.createAccount(accountParams); //account.setCustomHeader("Header1", "Header2"); // Now let's add our objects to the Core core.addAuthInfo(user); core.addAccount(account); // Also set the newly added account as default core.setDefaultAccount(account); core.setUserAgent("User", "Agent"); // Finally we need the Core to be started for the registration to happen (it could have been started before) core.start(); } void logout(){ i("logout"); Account account = core.getDefaultAccount(); if(account != null) { accountParams = account.getParams().clone(); accountParams.setRegisterEnabled(false); account.setParams(accountParams); } }SipPhone.java : 通话部分//拨打电话. @Override public void call(String number, boolean video) { i("call " + number + " video(" + video + ")"); String domain = PreferenceUtils.getStringFromDefault(App.getApp(), App.PREF_VOIP_IP, ""); String port = PreferenceUtils.getStringFromDefault(App.getApp(), App.PREF_VOIP_PORT, App.DEF_SIP_PORT); // As for everything we need to get the SIP URI of the remote and convert it to an Address String remoteSipUri = "sip:" + toNumber + "@" + domain + ":" + port; Address remoteAddress = factory.createAddress(remoteSipUri); if(remoteAddress == null)return; // If address parsing fails, we can't continue with outgoing call process // We also need a CallParams object // Create call params expects a Call object for incoming calls, but for outgoing we must use null safely CallParams params = core.createCallParams(null); // We can now configure it // Here we ask for no encryption but we could ask for ZRTP/SRTP/DTLS params.setMediaEncryption(MediaEncryption.None); params.enableVideo(video); //show preview before caling. //core.enableVideoPreview(video); // Finally we start the call core.inviteAddressWithParams(remoteAddress, params); //回声消除 // Call process can be followed in onCallStateChanged callback from core listener } //挂断 @Override public void hangup() { i("hangup"); if (core.getCallsNb() == 0) return; // If the call state isn't paused, we can get it using core.currentCall Call call = core.getCurrentCall() != null ? core.getCurrentCall() : core.getCalls()[0]; if(call != null) { // Terminating a call is quite simple call.terminate(); } } //接听/应答 @Override public void answer() { i("answer"); if(currentCall != null){ if(remoteHasVideo()) { enableCamera(); currentCall.getParams().enableVideo(true); } currentCall.accept(); } }SipPhone.java : 监听和回调//在initSip中使用. CoreListener coreListener = new CoreListenerStub(){ @Override public void onCallStateChanged(Core core, Call call, Call.State state, String message) { d("onCallStateChanged " + state); currentCall = call; if(state == Call.State.OutgoingProgress){ //呼出 }else if(state == Call.State.IncomingReceived){ //来电 }else if(state == Call.State.StreamsRunning){ //通话中, 有音视频流. }else if(state == Call.State.UpdatedByRemote){ //通话变化, 有可能变成语音, 也有可能是带视频... }else if(state == Call.State.Released){ //挂电或结束通话 }else if(state == Call.State.Error){ //出错. } } @Override public void onRegistrationStateChanged(Core core, ProxyConfig proxyConfig, RegistrationState state, String message) { //message: // case "io error": server offline. // i("onRegistrationStateChanged " + state + " with msg:" + message); //((Button)findViewById(R.id.btLogin)).setText(state == RegistrationState.Ok ? "Logout":"Login"); if(state == RegistrationState.Ok) { //登陆成功 }else{ //登出 } } };关于视频部分:如何设置视频显示的控件, 在通话呼起后可以调用这个函数.public void setVideoView(View v1, View v2){ core.setNativePreviewWindowId(v1); core.setNativeVideoWindowId(v2); }所有的功能接口, 请以参考源码及官方为主强烈建议下载linphone-android客户端源码并编译运行, 学习如何更好地使用SDK开发自己需要的功能配置文件 在优化视频通话的过程中, 接触到关于初始化配置的问题. 很多资料显示, 可能通过配置方件的方式, 配置优化音频参数来优化通话效果:Echo suppression does not workAndroid音视频通话——Linphone开发笔记总结2022-09-24-voice_communication_audio_codec.md大致的方法是:1.增加配置文件assets/linphone_factory或 assets/linphonerc_factoryres/raw/linphone_factory 或 res/raw/linphonerc_factory2.编写对应配置[sip] guess_hostname=1 register_only_when_network_is_up=1 auto_net_state_mon=1 auto_answer_replacing_calls=1 ping_with_options=0 use_cpim=1 zrtp_key_agreements_suites=MS_ZRTP_KEY_AGREEMENT_K255_KYB512 chat_messages_aggregation_delay=1000 chat_messages_aggregation=1 [sound] #remove this property for any application that is not Linphone public version itself ec_calibrator_cool_tones=1 # 打开回声消除 echocancellation=1 # MIC 增益 mic_gain_db=0.0 # 回放增益 playback_gain_db=0.0 [video] displaytype=MSAndroidTextureDisplay auto_resize_preview_to_keep_ratio=1 max_mosaic_size=vga3.打包到程序中运行.以上这些方法, 仅适用于linphone-android客户端源码, 针对基于SDK开发的话, 则需要在对应的地方加入载入配置文件的代码://参考 //-linphone-android/app/src/main/java/org/linphone/core/CorePreferences.kt //-linphone-android/app/src/main/java/org/linphone/LinphoneApplication.kt //在创建Core之前载入配置文件. Config config = factory.createConfigWithFactory(App.LINPHONE_CONFIG_DEF, App.LINPHONE_CONFIG_FAC); core = factory.createCoreWithConfig(config, App.getApp().getActivity());参考Ubuntu搭建简单SIP服务器并使用sipdroid测试一文详解SIP 协议- xiaxueliang - 博客园sipdroid
前言 在 Android 中,TTS全称叫做 Text to Speech,从字面就能理解它解决的问题是什么,把文本转为语音服务,意思就是你输入一段文本信息,然后Android 系统可以把这段文字播报出来。这种应用场景目前比较多是在各种语音助手APP上,很多手机系统集成商内部都有内置文本转语音服务,可以读当前页面上的文本信息。同样,在一些阅读类APP上我们也能看到相关服务,打开微信读书,里面就直接可以把当前页面直接用语音方式播放出来,特别适合哪种不方便拿着手机屏幕阅读的场景。 Android系统从1.6版本开始就支持TTS, 不过遗憾的是系统默认的TTS引擎:Pico TTS,并不支持中文。 在查找了许相关资料后, 发现很多的资源都已经失效, APK找不到, 对应的页面404. 更多的厂商则转成了开放平台甚至不再提供离线/免费服务.目前找到的离线TTS注:下面的链接可能需要科学上网才可以访问使用首先, 安装对应的TTS应用, 再在设置中设置对应的语音输出服务一般设置的步骤为: 设置>无障碍>文字转语音(TTS)输出程序调用只需使用SDK标准的TTS接口即可.在介绍TTS使用的文章中, 下面这一段的代码, 对于前面的科大讯飞或ITRI TTS并没什么效果, 只是多了一个弹窗, 当然, 也可以理解为, 这两个APP并没有按标准接口开发.//显示应用选择窗. Intent checkIntent = new Intent(); checkIntent.setAction(TextToSpeech.Engine.ACTION_CHECK_TTS_DATA); startActivityForResult(checkIntent, MY_DATA_CHECK_CODE); private TextToSpeech mTts; protected void onActivityResult( int requestCode, int resultCode, Intent data) { if (requestCode == MY_DATA_CHECK_CODE) { if (resultCode == TextToSpeech.Engine.CHECK_VOICE_DATA_PASS) { // success, create the TTS instance mTts = new TextToSpeech(this, this); } else { // missing data, install it Intent installIntent = new Intent(); installIntent.setAction(TextToSpeech.Engine.ACTION_INSTALL_TTS_DATA); startActivity(installIntent); } } }在程序中打印TTS所支持的语言及声音getAvailableLanguages和getVoices:if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) { Set<Locale> ava = mTts.getAvailableLanguages(); if (ava != null) { for (Locale l : ava) { Logger.v(TAG, "supported " + l.toString()); } } else { Logger.d(TAG, "no supported language"); } Set<Voice> voices = mTts.getVoices(); if(voices != null){ for(Voice v : voices){ Logger.d(TAG, "TTS Voice: " + v.toString()); } } } String engine = mTts.getDefaultEngine(); Logger.d(TAG, "TTS Engine = " + engine);2022-10-18 15:21:22.577 25266-25266 TextToSpeech com.tts.test I Connected to ComponentInfo{tw.pu.tts/tw.pu.tts.UttsService} 2022-10-18 15:21:22.582 25266-26006 TextToSpeech com.tts.test I Set up connection to ComponentInfo{tw.pu.tts/tw.pu.tts.UttsService} 2022-10-18 15:21:22.594 25266-25266 TTS com.tts.test D onInit 0 2022-10-18 15:21:22.650 25266-25266 TTS com.tts.test V supported zh 2022-10-18 15:21:22.650 25266-25266 TTS com.tts.test V supported en 2022-10-18 15:21:22.650 25266-25266 TTS com.tts.test V supported zh__#Hans 2022-10-18 15:21:22.650 25266-25266 TTS com.tts.test V supported zh__#Hant 2022-10-18 15:21:22.690 25266-25266 TTS com.tts.test D TTS Voice: Voice[Name: zh, locale: zh__#Hans, quality: 300, latency: 300, requiresNetwork: false, features: []] 2022-10-18 15:21:22.691 25266-25266 TTS com.tts.test D TTS Voice: Voice[Name: en, locale: en, quality: 300, latency: 300, requiresNetwork: false, features: []] 2022-10-18 15:21:22.691 25266-25266 TTS com.tts.test D TTS Voice: Voice[Name: zh, locale: zh, quality: 300, latency: 300, requiresNetwork: false, features: []] 2022-10-18 15:21:22.691 25266-25266 TTS com.tts.test D TTS Voice: Voice[Name: zh, locale: zh__#Hant, quality: 300, latency: 300, requiresNetwork: false, features: []] 2022-10-18 15:21:22.698 25266-25266 TTS com.tts.test D TTS Engine = tw.pu.tts注: TTS的功能需要在TextToSpeech.OnInitListener回调, 并确认状态正常后才可以开始正常工作完整代码TTS.javaimport android.annotation.SuppressLint; import android.app.Activity; import android.content.Context; import android.content.Intent; import android.media.AudioAttributes; import android.media.AudioManager; import android.speech.tts.TextToSpeech; import android.speech.tts.Voice; import java.util.Locale; import java.util.Set; public class TTS implements TextToSpeech.OnInitListener { final String TAG = "TTS"; TextToSpeech mTts; public TTS(Context context){ mTts = new TextToSpeech(context, this); } public TTS(Context context, TextToSpeech.OnInitListener lis){ mTts = new TextToSpeech(context, this); setOnInitListener(lis); } final int DATA_CHECK_CODE = 0x774; @Deprecated public TTS(Activity activity){ Intent checkIntent = new Intent(TextToSpeech.Engine.ACTION_CHECK_TTS_DATA); activity.startActivityForResult(checkIntent, 0x774); } @Deprecated public void onActivityResult(Activity activity, int requestCode, int resultCode, Intent data) { if (requestCode == DATA_CHECK_CODE) { if (resultCode == TextToSpeech.Engine.CHECK_VOICE_DATA_PASS) { // success, create the TTS instance mTts = new TextToSpeech(activity, this); } else { // missing data, install it Intent installIntent = new Intent(TextToSpeech.Engine.ACTION_INSTALL_TTS_DATA); activity.startActivity(installIntent); } } } public TextToSpeech getTts(){return mTts;} private void dump(){ if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) { Set<Locale> ava = mTts.getAvailableLanguages(); if (ava != null) { for (Locale l : ava) { Logger.v(TAG, "supported " + l.toString()); } //mTts.setLanguage(Locale.US); } else { Logger.d(TAG, "no supported language"); } Set<Voice> voices = mTts.getVoices(); if(voices != null){ for(Voice v : voices){ Logger.d(TAG, "TTS Voice: " + v.toString()); } } } String engine = mTts.getDefaultEngine(); Logger.d(TAG, "TTS Engine = " + engine); } public void setSpeechSpeed(float speed){ mTts.setSpeechRate(speed); } public void setVoiceFreq(float freq){ mTts.setPitch(freq); } public void speak(String s){ if(mTts == null){ Logger.e(TAG, "speak failed: TTS not ready"); return; } int res = mTts.speak(s, TextToSpeech.QUEUE_ADD, null); if(res != 0){ Logger.w(TAG, "speak failed: " + res); }else{ Logger.d(TAG, "speak " + s + " done"); } } public void stop(){ mTts.stop(); } @Override public void onInit(int status) { Logger.d(TAG, "onInit " + status); if(status == 0) { dump(); mTts.setPitch(1f); mTts.setSpeechRate(1f); if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) { AudioAttributes attr = new AudioAttributes.Builder().setLegacyStreamType(AudioManager.STREAM_MUSIC).build(); mTts.setAudioAttributes(attr); } } if(initLis != null)initLis.onInit(status); } TextToSpeech.OnInitListener initLis; public void setOnInitListener(TextToSpeech.OnInitListener initLis){ this.initLis = initLis; } }参考Android 中文語音引擎資源Android中使用自带TextToSpeech实现离线语音合成功能The 7 Best Text-to-Speech Apps for AndroidAndroid中提供的免费文字转语音功能TextToSpeech之快速入门用法(Android TTS 语音合成播报)An introduction to Text-To-Speech in Android附:文字转语音(TTS) 应用 (APK)
平台 R K 3568 + A n d r o i d 11 RK3568 + Android 11RK3568+Android11概述官方的说明 如果 Android 应用的界面线程处于阻塞状态的时间过长,会触发“应用无响应”(ANR) 错误。如果应用位于前台,系统会向用户显示一个对话框,ANR 对话框会为用户提供强制退出应用的选项。 ANR 处理流程首先, 3个ANR的时间定义: 通过调试: adb shell dumpsys input中查看窗口信息的dispatchingTimeout, 不同的窗口可能是不一样的, 这得看实际的时间设定, 如下3个值都设置为5秒, 那显示的都为5秒.App如Launhcer:frameworks/base/services/core/java/com/android/server/wm/ActivityTaskManagerService.java//当前的超时设置为5's public static final int KEY_DISPATCHING_TIMEOUT_MS = 5 * 1000;SystemUI的导航栏和状态栏:frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.java/// // 这个时间关联到的是: // /// // Default input dispatching timeout in nanoseconds. static final long DEFAULT_INPUT_DISPATCHING_TIMEOUT_NANOS = 5000 * 1000000L; h.dispatchingTimeoutNanos = DEFAULT_INPUT_DISPATCHING_TIMEOUT_NANOS;frameworks/native/services/inputflinger/dispatcher/InputDispatcher.cpp// Default input dispatching timeout if there is no focused application or paused window // from which to determine an appropriate dispatching timeout. constexpr std::chrono::nanoseconds DEFAULT_INPUT_DISPATCHING_TIMEOUT = 5s;第二, 字符串定义(frameworks/base/core/res 目录下):<string name="anr_activity_application" msgid="8121716632960340680">"<xliff:g id="APPLICATION">%2$s</xliff:g>没有响应"</string> <string name="anr_activity_process" msgid="3477362583767128667">"<xliff:g id="ACTIVITY">%1$s</xliff:g>没有响应"</string> <string name="anr_application_process" msgid="4978772139461676184">"<xliff:g id="APPLICATION">%1$s</xliff:g>没有响应"</string> <string name="anr_process" msgid="1664277165911816067">"进程“<xliff:g id="PROCESS">%1$s</xliff:g>”没有响应"</string> <string name="force_close" msgid="9035203496368973803">"确定"</string> <string name="report" msgid="2149194372340349521">"报告"</string> <string name="wait" msgid="7765985809494033348">"等待"</string>时序关键代码frameworks/native/services/inputflinger/dispatcher/InputDispatcher.cppvoid InputDispatcher::doNotifyAnrLockedInterruptible(CommandEntry* commandEntry) { sp<IBinder> token = commandEntry->inputChannel ? commandEntry->inputChannel->getConnectionToken() : nullptr; mLock.unlock(); const nsecs_t timeoutExtension = mPolicy->notifyAnr(commandEntry->inputApplicationHandle, token, commandEntry->reason); mLock.lock(); if (timeoutExtension > 0) { extendAnrTimeoutsLocked(commandEntry->inputApplicationHandle, token, timeoutExtension); } else { // stop waking up for events in this connection, it is already not responding sp<Connection> connection = getConnectionLocked(token); if (connection == nullptr) { return; } cancelEventsForAnrLocked(connection); } } void InputDispatcher::onAnrLocked(const sp<Connection>& connection) { // Since we are allowing the policy to extend the timeout, maybe the waitQueue // is already healthy again. Don't raise ANR in this situation if (connection->waitQueue.empty()) { ALOGI("Not raising ANR because the connection %s has recovered", connection->inputChannel->getName().c_str()); return; } /** * The "oldestEntry" is the entry that was first sent to the application. That entry, however, * may not be the one that caused the timeout to occur. One possibility is that window timeout * has changed. This could cause newer entries to time out before the already dispatched * entries. In that situation, the newest entries caused ANR. But in all likelihood, the app * processes the events linearly. So providing information about the oldest entry seems to be * most useful. */ DispatchEntry* oldestEntry = *connection->waitQueue.begin(); const nsecs_t currentWait = now() - oldestEntry->deliveryTime; std::string reason = android::base::StringPrintf("%s is not responding. Waited %" PRId64 "ms for %s", connection->inputChannel->getName().c_str(), ns2ms(currentWait), oldestEntry->eventEntry->getDescription().c_str()); updateLastAnrStateLocked(getWindowHandleLocked(connection->inputChannel->getConnectionToken()), reason); std::unique_ptr<CommandEntry> commandEntry = std::make_unique<CommandEntry>(&InputDispatcher::doNotifyAnrLockedInterruptible); commandEntry->inputApplicationHandle = nullptr; commandEntry->inputChannel = connection->inputChannel; commandEntry->reason = std::move(reason); postCommandLocked(std::move(commandEntry)); } /** * Check if any of the connections' wait queues have events that are too old. * If we waited for events to be ack'ed for more than the window timeout, raise an ANR. * Return the time at which we should wake up next. */ nsecs_t InputDispatcher::processAnrsLocked() { const nsecs_t currentTime = now(); nsecs_t nextAnrCheck = LONG_LONG_MAX; // Check if we are waiting for a focused window to appear. Raise ANR if waited too long if (mNoFocusedWindowTimeoutTime.has_value() && mAwaitedFocusedApplication != nullptr) { if (currentTime >= *mNoFocusedWindowTimeoutTime) { onAnrLocked(mAwaitedFocusedApplication); mAwaitedFocusedApplication.clear(); return LONG_LONG_MIN; } else { // Keep waiting const nsecs_t millisRemaining = ns2ms(*mNoFocusedWindowTimeoutTime - currentTime); ALOGW("Still no focused window. Will drop the event in %" PRId64 "ms", millisRemaining); nextAnrCheck = *mNoFocusedWindowTimeoutTime; } } // Check if any connection ANRs are due nextAnrCheck = std::min(nextAnrCheck, mAnrTracker.firstTimeout()); if (currentTime < nextAnrCheck) { // most likely scenario return nextAnrCheck; // everything is normal. Let's check again at nextAnrCheck } // If we reached here, we have an unresponsive connection. sp<Connection> connection = getConnectionLocked(mAnrTracker.firstToken()); if (connection == nullptr) { ALOGE("Could not find connection for entry %" PRId64, mAnrTracker.firstTimeout()); return nextAnrCheck; } connection->responsive = false; // Stop waking up for this unresponsive connection mAnrTracker.eraseToken(connection->inputChannel->getConnectionToken()); //ANR触发位置 onAnrLocked(connection); return LONG_LONG_MIN; } void InputDispatcher::dispatchOnce() { nsecs_t nextWakeupTime = LONG_LONG_MAX; { // acquire lock std::scoped_lock _l(mLock); mDispatcherIsAlive.notify_all(); // Run a dispatch loop if there are no pending commands. // The dispatch loop might enqueue commands to run afterwards. if (!haveCommandsLocked()) { dispatchOnceInnerLocked(&nextWakeupTime); } // Run all pending commands if there are any. // If any commands were run then force the next poll to wake up immediately. if (runCommandsLockedInterruptible()) { nextWakeupTime = LONG_LONG_MIN; } // If we are still waiting for ack on some events, // we might have to wake up earlier to check if an app is anr'ing. const nsecs_t nextAnrCheck = processAnrsLocked(); nextWakeupTime = std::min(nextWakeupTime, nextAnrCheck); // We are about to enter an infinitely long sleep, because we have no commands or // pending or queued events if (nextWakeupTime == LONG_LONG_MAX) { mDispatcherEnteredIdle.notify_all(); } } // release lock // Wait for callback or timeout or wake. (make sure we round up, not down) nsecs_t currentTime = now(); int timeoutMillis = toMillisecondTimeoutDelay(currentTime, nextWakeupTime); mLooper->pollOnce(timeoutMillis); }frameworks/base/services/core/jni/com_android_server_input_InputManagerService.cppnsecs_t NativeInputManager::notifyAnr(const sp<InputApplicationHandle>& inputApplicationHandle, const sp<IBinder>& token, const std::string& reason) { #if DEBUG_INPUT_DISPATCHER_POLICY ALOGD("notifyANR"); #endif ATRACE_CALL(); JNIEnv* env = jniEnv(); ScopedLocalFrame localFrame(env); jobject inputApplicationHandleObj = getInputApplicationHandleObjLocalRef(env, inputApplicationHandle); jobject tokenObj = javaObjectForIBinder(env, token); jstring reasonObj = env->NewStringUTF(reason.c_str()); jlong newTimeout = env->CallLongMethod(mServiceObj, gServiceClassInfo.notifyANR, inputApplicationHandleObj, tokenObj, reasonObj); if (checkAndClearExceptionFromCallback(env, "notifyANR")) { newTimeout = 0; // abort dispatch } else { assert(newTimeout >= 0); } return newTimeout; } GET_METHOD_ID(gServiceClassInfo.notifyANR, clazz, "notifyANR", "(Landroid/view/InputApplicationHandle;Landroid/os/IBinder;Ljava/lang/String;)J");frameworks/base/services/core/java/com/android/server/input/InputManagerService.java// Native callback. private long notifyANR(InputApplicationHandle inputApplicationHandle, IBinder token, String reason) { return mWindowManagerCallbacks.notifyANR(inputApplicationHandle, token, reason); }frameworks/base/services/core/java/com/android/server/wm/InputManagerCallback.java/** * Notifies the window manager about an application that is not responding. * Returns a new timeout to continue waiting in nanoseconds, or 0 to abort dispatch. * * Called by the InputManager. */ @Override public long notifyANR(InputApplicationHandle inputApplicationHandle, IBinder token, String reason) { final long startTime = SystemClock.uptimeMillis(); try { return notifyANRInner(inputApplicationHandle, token, reason); } finally { // Log the time because the method is called from InputDispatcher thread. It shouldn't // take too long that may affect input response time. Slog.d(TAG_WM, "notifyANR took " + (SystemClock.uptimeMillis() - startTime) + "ms"); } } private long notifyANRInner(InputApplicationHandle inputApplicationHandle, IBinder token, String reason) { ActivityRecord activity = null; WindowState windowState = null; boolean aboveSystem = false; int windowPid = INVALID_PID; preDumpIfLockTooSlow(); //TODO(b/141764879) Limit scope of wm lock when input calls notifyANR synchronized (mService.mGlobalLock) { // Check if we can blame a window if (token != null) { windowState = mService.mInputToWindowMap.get(token); if (windowState != null) { activity = windowState.mActivityRecord; windowPid = windowState.mSession.mPid; // Figure out whether this window is layered above system windows. // We need to do this here to help the activity manager know how to // layer its ANR dialog. aboveSystem = isWindowAboveSystem(windowState); } } // Check if we can blame an embedded window if (token != null && windowState == null) { EmbeddedWindow embeddedWindow = mService.mEmbeddedWindowController.get(token); if (embeddedWindow != null) { windowPid = embeddedWindow.mOwnerPid; WindowState hostWindowState = embeddedWindow.mHostWindowState; if (hostWindowState == null) { // The embedded window has no host window and we cannot easily determine // its z order. Try to place the anr dialog as high as possible. aboveSystem = true; } else { aboveSystem = isWindowAboveSystem(hostWindowState); } } } // Check if we can blame an activity. If we don't have an activity to blame, pull out // the token passed in via input application handle. This can happen if there are no // focused windows but input dispatcher knows the focused app. if (activity == null && inputApplicationHandle != null) { activity = ActivityRecord.forTokenLocked(inputApplicationHandle.token); } if (windowState != null) { Slog.i(TAG_WM, "Input event dispatching timed out " + "sending to " + windowState.mAttrs.getTitle() + ". Reason: " + reason); } else if (activity != null) { Slog.i(TAG_WM, "Input event dispatching timed out " + "sending to application " + activity.stringName + ". Reason: " + reason); } else { Slog.i(TAG_WM, "Input event dispatching timed out " + ". Reason: " + reason); } mService.saveANRStateLocked(activity, windowState, reason); } // All the calls below need to happen without the WM lock held since they call into AM. mService.mAtmInternal.saveANRState(reason); if (activity != null && activity.appToken != null) { // Notify the activity manager about the timeout and let it decide whether // to abort dispatching or keep waiting. final boolean abort = activity.keyDispatchingTimedOut(reason, windowPid); if (!abort) { // The activity manager declined to abort dispatching. // Wait a bit longer and timeout again later. return activity.mInputDispatchingTimeoutNanos; } } else if (windowState != null || windowPid != INVALID_PID) { // Notify the activity manager about the timeout and let it decide whether // to abort dispatching or keep waiting. long timeout = mService.mAmInternal.inputDispatchingTimedOut(windowPid, aboveSystem, reason); if (timeout >= 0) { // The activity manager declined to abort dispatching. // Wait a bit longer and timeout again later. return timeout * 1000000L; // nanoseconds } } return 0; // abort dispatching }frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java long inputDispatchingTimedOut(int pid, final boolean aboveSystem, String reason) { if (checkCallingPermission(FILTER_EVENTS) != PackageManager.PERMISSION_GRANTED) { throw new SecurityException("Requires permission " + FILTER_EVENTS); } ProcessRecord proc; long timeout; synchronized (this) { synchronized (mPidsSelfLocked) { proc = mPidsSelfLocked.get(pid); } timeout = proc != null ? proc.getInputDispatchingTimeout() : KEY_DISPATCHING_TIMEOUT_MS; } if (inputDispatchingTimedOut(proc, null, null, null, null, aboveSystem, reason)) { return -1; } return timeout; } final class UiHandler extends Handler { //Ignored.... @Override public void handleMessage(Message msg) { switch (msg.what) { case SHOW_ERROR_UI_MSG: { mAppErrors.handleShowAppErrorUi(msg); ensureBootCompleted(); } break; case SHOW_NOT_RESPONDING_UI_MSG: { mAppErrors.handleShowAnrUi(msg); ensureBootCompleted(); } break; //Ignored ..... }frameworks/base/services/core/java/com/android/server/am/AnrHelper.javavoid appNotResponding(ProcessRecord anrProcess, String annotation) { appNotResponding(anrProcess, null /* activityShortComponentName */, null /* aInfo */, null /* parentShortComponentName */, null /* parentProcess */, false /* aboveSystem */, annotation); } void appNotResponding(ProcessRecord anrProcess, String activityShortComponentName, ApplicationInfo aInfo, String parentShortComponentName, WindowProcessController parentProcess, boolean aboveSystem, String annotation) { synchronized (mAnrRecords) { mAnrRecords.add(new AnrRecord(anrProcess, activityShortComponentName, aInfo, parentShortComponentName, parentProcess, aboveSystem, annotation)); } startAnrConsumerIfNeeded(); } private void startAnrConsumerIfNeeded() { if (mRunning.compareAndSet(false, true)) { new AnrConsumerThread().start(); } }frameworks/base/services/core/java/com/android/server/am/ProcessRecord.javavoid appNotResponding(String activityShortComponentName, ApplicationInfo aInfo, String parentShortComponentName, WindowProcessController parentProcess, boolean aboveSystem, String annotation, boolean onlyDumpSelf) { //Ignored... // mUiHandler can be null if the AMS is constructed with injector only. This will only // happen in tests. if (mService.mUiHandler != null) { // Bring up the infamous App Not Responding dialog Message msg = Message.obtain(); msg.what = ActivityManagerService.SHOW_NOT_RESPONDING_UI_MSG; msg.obj = new AppNotRespondingDialog.Data(this, aInfo, aboveSystem); mService.mUiHandler.sendMessage(msg); } } } class ErrorDialogControlle //AppErrors 调用 void showAnrDialogs(AppNotRespondingDialog.Data data) { List<Context> contexts = getDisplayContexts(isSilentAnr() /* lastUsedOnly */); mAnrDialogs = new ArrayList<>(); for (int i = contexts.size() - 1; i >= 0; i--) { final Context c = contexts.get(i); mAnrDialogs.add(new AppNotRespondingDialog(mService, c, data)); } mService.mUiHandler.post(() -> { List<AppNotRespondingDialog> dialogs; synchronized (mService) { dialogs = mAnrDialogs; } if (dialogs != null) { forAllDialogs(dialogs, Dialog::show); } }); }frameworks/base/services/core/java/com/android/server/am/AppErrors.java void handleShowAnrUi(Message msg) { List<VersionedPackage> packageList = null; synchronized (mService) { AppNotRespondingDialog.Data data = (AppNotRespondingDialog.Data) msg.obj; final ProcessRecord proc = data.proc; if (proc == null) { Slog.e(TAG, "handleShowAnrUi: proc is null"); return; } if (!proc.isPersistent()) { packageList = proc.getPackageListWithVersionCode(); } if (proc.getDialogController().hasAnrDialogs()) { Slog.e(TAG, "App already has anr dialog: " + proc); MetricsLogger.action(mContext, MetricsProto.MetricsEvent.ACTION_APP_ANR, AppNotRespondingDialog.ALREADY_SHOWING); return; } boolean showBackground = Settings.Secure.getInt(mContext.getContentResolver(), Settings.Secure.ANR_SHOW_BACKGROUND, 0) != 0; if (mService.mAtmInternal.canShowErrorDialogs() || showBackground) { proc.getDialogController().showAnrDialogs(data); //Ignored ..... }frameworks/base/services/core/java/com/android/server/am/AppNotRespondingDialog.java对话框的代码就省略吧.至此, 显示ANR对话框的流程走完InputDispatcher中窗口句柄frameworks/native/services/surfaceflinger/SurfaceFlinger.cppvoid SurfaceFlinger::updateInputFlinger() { ATRACE_CALL(); if (!mInputFlinger) { return; } if (mVisibleRegionsDirty || mInputInfoChanged) { mInputInfoChanged = false; updateInputWindowInfo(); } else if (mInputWindowCommands.syncInputWindows) { // If the caller requested to sync input windows, but there are no // changes to input windows, notify immediately. setInputWindowsFinished(); } mInputWindowCommands.clear(); } void SurfaceFlinger::updateInputWindowInfo() { std::vector<InputWindowInfo> inputHandles; mDrawingState.traverseInReverseZOrder([&](Layer* layer) { if (layer->needsInputInfo()) { // When calculating the screen bounds we ignore the transparent region since it may // result in an unwanted offset. inputHandles.push_back(layer->fillInputInfo()); } }); mInputFlinger->setInputWindows(inputHandles, mInputWindowCommands.syncInputWindows ? mSetInputWindowsListener : nullptr); }frameworks/native/services/inputflinger/InputManager.cppvoid InputManager::setInputWindows(const std::vector<InputWindowInfo>& infos, const sp<ISetInputWindowsListener>& setInputWindowsListener) { std::unordered_map<int32_t, std::vector<sp<InputWindowHandle>>> handlesPerDisplay; std::vector<sp<InputWindowHandle>> handles; for (const auto& info : infos) { handlesPerDisplay.emplace(info.displayId, std::vector<sp<InputWindowHandle>>()); handlesPerDisplay[info.displayId].push_back(new BinderWindowHandle(info)); } mDispatcher->setInputWindows(handlesPerDisplay); if (setInputWindowsListener) { setInputWindowsListener->onSetInputWindowsFinished(); } }frameworks/native/services/inputflinger/dispatcher/InputDispatcher.cpp/// // 通过InputManagerService 添加窗口句柄 // /// /** * Called from InputManagerService, update window handle list by displayId that can receive input. * A window handle contains information about InputChannel, Touch Region, Types, Focused,... * If set an empty list, remove all handles from the specific display. * For focused handle, check if need to change and send a cancel event to previous one. * For removed handle, check if need to send a cancel event if already in touch. */ void InputDispatcher::setInputWindowsLocked(){ updateWindowHandlesForDisplayLocked... } /// // 更新mWindowHandlesByDisplay中 // /// void InputDispatcher::updateWindowHandlesForDisplayLocked( const std::vector<sp<InputWindowHandle>>& inputWindowHandles, int32_t displayId) { //Ignored..... // Insert or replace mWindowHandlesByDisplay[displayId] = newHandles; } /// // 从mWindowHandlesByDisplay中查询当前窗口 // /// sp<InputWindowHandle> InputDispatcher::getWindowHandleLocked( const sp<IBinder>& windowHandleToken) const { if (windowHandleToken == nullptr) { return nullptr; } for (auto& it : mWindowHandlesByDisplay) { const std::vector<sp<InputWindowHandle>> windowHandles = it.second; for (const sp<InputWindowHandle>& windowHandle : windowHandles) { if (windowHandle->getToken() == windowHandleToken) { return windowHandle; } } } return nullptr; } nsecs_t InputDispatcher::getDispatchingTimeoutLocked(const sp<IBinder>& token) { sp<InputWindowHandle> window = getWindowHandleLocked(token); if (window != nullptr) { return window->getDispatchingTimeout(DEFAULT_INPUT_DISPATCHING_TIMEOUT).count(); } return DEFAULT_INPUT_DISPATCHING_TIMEOUT.count(); }frameworks/base/services/core/java/com/android/server/wm/WindowProcessController.javapublic long getInputDispatchingTimeout() { synchronized (mAtm.mGlobalLock) { return isInstrumenting() || isUsingWrapper() ? INSTRUMENTATION_KEY_DISPATCHING_TIMEOUT_MS : KEY_DISPATCHING_TIMEOUT_MS; } }frameworks/base/services/core/java/com/android/server/am/ProcessRecord.javapublic long getInputDispatchingTimeout() { return mWindowProcessController.getInputDispatchingTimeout(); }扩展编译及替换#编译 mmm frameworks/native/services/inputflinger/ -j2 #替换 adb push out/target/product/rk3566_r/system/bin/inputflinger /system/bin/ adb push out/target/product/rk3566_r/system/lib/libinputflinger.so /system/lib/ adb push out/target/product/rk3566_r/system/lib64/libinputflinger.so /system/lib64/调试: adb shell dumpsys input0: name='Window{57ce99a u0 NavigationBar0}', displayId=0, portalToDisplayId=-1, paused=false, hasFocus=false, hasWallpaper=false, visible=false, canReceiveKeys=false, flags=0x21840068, type=0x000007e3, frame=[0,752][1280,800], globalScale=1.000000, windowScale=(1.000000,1.000000), touchableRegion=[0,752][1280,800], inputFeatures=0x00000000, ownerPid=614, ownerUid=10119, dispatchingTimeout=7000ms 1: name='Window{61c1033 u0 StatusBar}', displayId=0, portalToDisplayId=-1, paused=false, hasFocus=false, hasWallpaper=false, visible=false, canReceiveKeys=false, flags=0x81800408, type=0x000007d0, frame=[0,0][1280,24], globalScale=1.000000, windowScale=(1.000000,1.000000), touchableRegion=[0,0][1280,24], inputFeatures=0x00000000, ownerPid=614, ownerUid=10119, dispatchingTimeout=7000ms 2: name='Window{e0e47c4 u0 com.android.launcher3/com.android.launcher3.uioverrides.QuickstepLauncher}', displayId=0, portalToDisplayId=-1, paused=false, hasFocus=true, hasWallpaper=true, visible=true, canReceiveKeys=true, flags=0x81910120, type=0x00000001, frame=[0,0][1280,800], globalScale=1.000000, windowScale=(1.000000,1.000000), touchableRegion=[0,0][1280,800], inputFeatures=0x00000000, ownerPid=1039, ownerUid=10121, dispatchingTimeout=15000ms 3: name='Window{bbadc9c u0 com.android.systemui.ImageWallpaper}', displayId=0, portalToDisplayId=-1, paused=false, hasFocus=false, hasWallpaper=false, visible=true, canReceiveKeys=false, flags=0x00014318, type=0x000007dd, frame=[-64,-304][1344,1104], globalScale=1.000000, windowScale=(0.909091,0.909091), touchableRegion=[-64,-304][1344,1104], inputFeatures=0x00000000, ownerPid=614, ownerUid=10119, dispatchingTimeout=7000ms参考ANRAndroid ANR:原理分析及解决办法
平台 RK3566 + Android 11问题 在测试过程中, 发现第三方应用的开机自启时间加长了, 在显示Launcher后, 还需要等待超过1分钟的时间. 后续在查LOG中发现以以下异常LOG(Timeout of broadcast BroadcastRecord)://第一个收到 09-13 17:45:03.406 D/WifiSleepController( 432): onReceive, action=android.intent.action.BOOT_COMPLETED //异常LOG位置 09-13 17:46:07.077 W/BroadcastQueue( 432): Timeout of broadcast BroadcastRecord{35f0038 u0 android.intent.action.BOOT_COMPLETED} - receiver=android.os.BinderProxy@e7eb8bf, started 60000ms ago 09-13 17:46:07.077 W/BroadcastQueue( 432): Receiver during timeout of BroadcastRecord{35f0038 u0 android.intent.action.BOOT_COMPLETED} : ResolveInfo{af90b8c com.android.phone/.vvm.VvmSimStateTracker m=0x108000}started 60000ms ago 表明是开始于1分钟前的广播处理超时, 这时候广播会继续下发, 这时候第三方应用才开始接收到开机广播并执行相应的操作, 比如自启.虽然不是关键的位置, 还是记录下源码中LOG输出位置frameworks/base/services/core/java/com/android/server/am/BroadcastQueue.javafinal void broadcastTimeoutLocked(boolean fromMsg) { if (fromMsg) { mPendingBroadcastTimeoutMessage = false; } if (mDispatcher.isEmpty() || mDispatcher.getActiveBroadcastLocked() == null) { return; } long now = SystemClock.uptimeMillis(); BroadcastRecord r = mDispatcher.getActiveBroadcastLocked(); if (fromMsg) { if (!mService.mProcessesReady) { // Only process broadcast timeouts if the system is ready; some early // broadcasts do heavy work setting up system facilities return; } // If the broadcast is generally exempt from timeout tracking, we're done if (r.timeoutExempt) { if (DEBUG_BROADCAST) { Slog.i(TAG_BROADCAST, "Broadcast timeout but it's exempt: " + r.intent.getAction()); } return; } long timeoutTime = r.receiverTime + mConstants.TIMEOUT; if (timeoutTime > now) { // We can observe premature timeouts because we do not cancel and reset the // broadcast timeout message after each receiver finishes. Instead, we set up // an initial timeout then kick it down the road a little further as needed // when it expires. if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Premature timeout [" + mQueueName + "] @ " + now + ": resetting BROADCAST_TIMEOUT_MSG for " + timeoutTime); setBroadcastTimeoutLocked(timeoutTime); return; } } if (r.state == BroadcastRecord.WAITING_SERVICES) { // In this case the broadcast had already finished, but we had decided to wait // for started services to finish as well before going on. So if we have actually // waited long enough time timeout the broadcast, let's give up on the whole thing // and just move on to the next. Slog.i(TAG, "Waited long enough for: " + (r.curComponent != null ? r.curComponent.flattenToShortString() : "(null)")); r.curComponent = null; r.state = BroadcastRecord.IDLE; processNextBroadcast(false); return; } // If the receiver app is being debugged we quietly ignore unresponsiveness, just // tidying up and moving on to the next broadcast without crashing or ANRing this // app just because it's stopped at a breakpoint. final boolean debugging = (r.curApp != null && r.curApp.isDebugging()); Slog.w(TAG, "Timeout of broadcast " + r + " - receiver=" + r.receiver + ", started " + (now - r.receiverTime) + "ms ago"); }跟踪 首先, 这个问题从Log上可以看出, 在传递广播的过程中, 卡在了其它的某个进程里, 考虑的顺序如下:1.是否在VvmSimStateTracker.onReceive中处理了比较耗时的操作2.是否进程初始化执行了耗时操作, 进程中的PhoneApp 1.是否在VvmSimStateTracker.onReceive中处理了比较耗时的操作注册广播: packages/services/Telephony/src/com/android/phone/AndroidManifest.xml <receiver android:name="com.android.phone.vvm.VvmSimStateTracker" android:exported="false" androidprv:systemUserOnly="true"> <intent-filter> <action android:name="android.intent.action.BOOT_COMPLETED"/> <action android:name="android.telephony.action.CARRIER_CONFIG_CHANGED"/> <action android:name="android.intent.action.SIM_STATE_CHANGED"/> </intent-filter> </receiver>广播处理:packages/services/Telephony/src/com/android/phone/vvm/VvmSimStateTracker.javapublic void onReceive(Context context, Intent intent) { final String action = intent.getAction(); if (action == null) { VvmLog.w(TAG, "Null action for intent."); return; } VvmLog.i(TAG, action); switch (action) { case Intent.ACTION_BOOT_COMPLETED: onBootCompleted(context); break; //Ignore.... } private void onBootCompleted(Context context) { for (PhoneAccountHandle phoneAccountHandle : sPreBootHandles) { TelephonyManager telephonyManager = getTelephonyManager(context, phoneAccountHandle); if (telephonyManager == null) { continue; } if (telephonyManager.getServiceState().getState() == ServiceState.STATE_IN_SERVICE) { sListeners.put(phoneAccountHandle, null); sendConnected(context, phoneAccountHandle); } else { listenToAccount(context, phoneAccountHandle); } } sPreBootHandles.clear(); } 2.是否进程初始化执行了耗时操作, 进程中的PhoneAppApplication声明: packages/services/Telephony/src/com/android/phone/AndroidManifest.xml<application android:name="PhoneApp" android:persistent="true" android:label="@string/phoneAppLabel" android:icon="@mipmap/ic_launcher_phone" android:allowBackup="false" android:supportsRtl="true" android:usesCleartextTraffic="true" android:defaultToDeviceProtectedStorage="true" android:directBootAware="true">Application: packages/services/Telephony/src/com/android/phone/PhoneApp.javapublic class PhoneApp extends Application { PhoneGlobals mPhoneGlobals; public PhoneApp() { } @Override public void onCreate() { if (UserHandle.myUserId() == 0) { // We are running as the primary user, so should bring up the // global phone state. mPhoneGlobals = new PhoneGlobals(this); mPhoneGlobals.onCreate(); TelecomAccountRegistry.getInstance(this).setupOnBoot(); } } }结论通过在1和2的代码中插入LOG后, 最终确定, 问题是出在了Application的初始化上, 也就是说, Phone的进程卡在了onCreate这个函数上.Phone进程为什么卡住?关键部分代码:packages/services/Telephony/src/com/android/phone/PhoneGlobals.javapublic void onCreate() { if (VDBG) Log.v(LOG_TAG, "onCreate()..."); ContentResolver resolver = getContentResolver(); // Cache the "voice capable" flag. // This flag currently comes from a resource (which is // overrideable on a per-product basis): sVoiceCapable = ((TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE)) .isVoiceCapable(); // ...but this might eventually become a PackageManager "system // feature" instead, in which case we'd do something like: // sVoiceCapable = // getPackageManager().hasSystemFeature(PackageManager.FEATURE_TELEPHONY_VOICE_CALLS); if (mCM == null) { // Initialize AnomalyReporter early so that it can be used AnomalyReporter.initialize(this); // Inject telephony component factory if configured using other jars. XmlResourceParser parser = getResources().getXml(R.xml.telephony_injection); TelephonyComponentFactory.getInstance().injectTheComponentFactory(parser); // Initialize the telephony framework PhoneFactory.makeDefaultPhones(this); //ignored... }frameworks/opt/telephony/src/java/com/android/internal/telephony/PhoneFactory.java public static void makeDefaultPhones(Context context) { makeDefaultPhone(context); } @UnsupportedAppUsage public static void makeDefaultPhone(Context context) { synchronized (sLockProxyPhones) { if (!sMadeDefaults) { sContext = context; // create the telephony device controller. TelephonyDevController.create(); TelephonyMetrics metrics = TelephonyMetrics.getInstance(); metrics.setContext(context); int retryCount = 0; for(;;) { boolean hasException = false; retryCount ++; try { // use UNIX domain socket to // prevent subsequent initialization new LocalServerSocket("com.android.internal.telephony"); } catch (java.io.IOException ex) { hasException = true; } if ( !hasException ) { break; } else if (retryCount > SOCKET_OPEN_MAX_RETRY) { throw new RuntimeException("PhoneFactory probably already running"); } else { try { Thread.sleep(SOCKET_OPEN_RETRY_MILLIS); } catch (InterruptedException er) { } } } // register statsd pullers. sMetricsCollector = new MetricsCollector(context); sPhoneNotifier = new DefaultPhoneNotifier(context); int cdmaSubscription = CdmaSubscriptionSourceManager.getDefault(context); Rlog.i(LOG_TAG, "Cdma Subscription set to " + cdmaSubscription); /* In case of multi SIM mode two instances of Phone, RIL are created, where as in single SIM mode only instance. isMultiSimEnabled() function checks whether it is single SIM or multi SIM mode */ int numPhones = TelephonyManager.getDefault().getActiveModemCount(); int[] networkModes = new int[numPhones]; sPhones = new Phone[numPhones]; sCommandsInterfaces = new RIL[numPhones]; sTelephonyNetworkFactories = new TelephonyNetworkFactory[numPhones]; for (int i = 0; i < numPhones; i++) { // reads the system properties and makes commandsinterface // Get preferred network type. networkModes[i] = RILConstants.PREFERRED_NETWORK_MODE; Rlog.i(LOG_TAG, "Network Mode set to " + Integer.toString(networkModes[i])); sCommandsInterfaces[i] = new RIL(context, networkModes[i], cdmaSubscription, i); } // Ignored }frameworks/opt/telephony/src/java/com/android/internal/telephony/RIL.java @UnsupportedAppUsage public RIL(Context context, int preferredNetworkType, int cdmaSubscription, Integer instanceId) { super(context); if (RILJ_LOGD) { riljLog("RIL: init preferredNetworkType=" + preferredNetworkType + " cdmaSubscription=" + cdmaSubscription + ")"); } mContext = context; mCdmaSubscription = cdmaSubscription; mPreferredNetworkType = preferredNetworkType; mPhoneType = RILConstants.NO_PHONE; mPhoneId = instanceId == null ? 0 : instanceId; if (isRadioBugDetectionEnabled()) { mRadioBugDetector = new RadioBugDetector(context, mPhoneId); } TelephonyManager tm = (TelephonyManager) context.getSystemService( Context.TELEPHONY_SERVICE); mIsCellularSupported = tm.isVoiceCapable() || tm.isSmsCapable() || tm.isDataCapable(); mRadioResponse = new RadioResponse(this); mRadioIndication = new RadioIndication(this); mOemHookResponse = new OemHookResponse(this); mOemHookIndication = new OemHookIndication(this); mRilHandler = new RilHandler(); mRadioProxyDeathRecipient = new RadioProxyDeathRecipient(); PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE); mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, RILJ_WAKELOCK_TAG); mWakeLock.setReferenceCounted(false); mAckWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, RILJ_ACK_WAKELOCK_NAME); mAckWakeLock.setReferenceCounted(false); mWakeLockTimeout = TelephonyProperties.wake_lock_timeout() .orElse(DEFAULT_WAKE_LOCK_TIMEOUT_MS); mAckWakeLockTimeout = TelephonyProperties.wake_lock_timeout() .orElse(DEFAULT_ACK_WAKE_LOCK_TIMEOUT_MS); mWakeLockCount = 0; mRILDefaultWorkSource = new WorkSource(context.getApplicationInfo().uid, context.getPackageName()); mActiveWakelockWorkSource = new WorkSource(); TelephonyDevController tdc = TelephonyDevController.getInstance(); tdc.registerRIL(this); // set radio callback; needed to set RadioIndication callback (should be done after // wakelock stuff is initialized above as callbacks are received on separate binder threads) getRadioProxy(null); getOemHookProxy(null); if (RILJ_LOGD) { riljLog("Radio HAL version: " + mRadioVersion); } } /** Returns a {@link IRadio} instance or null if the service is not available. */ @VisibleForTesting public synchronized IRadio getRadioProxy(Message result) { if (!SubscriptionManager.isValidPhoneId(mPhoneId)) return null; if (!mIsCellularSupported) { if (RILJ_LOGV) riljLog("getRadioProxy: Not calling getService(): wifi-only"); if (result != null) { AsyncResult.forMessage(result, null, CommandException.fromRilErrno(RADIO_NOT_AVAILABLE)); result.sendToTarget(); } return null; } if (mRadioProxy != null) { return mRadioProxy; } try { if (mDisabledRadioServices.contains(mPhoneId)) { riljLoge("getRadioProxy: mRadioProxy for " + HIDL_SERVICE_NAME[mPhoneId] + " is disabled"); } else { try { mRadioProxy = android.hardware.radio.V1_5.IRadio.getService( HIDL_SERVICE_NAME[mPhoneId], true); mRadioVersion = RADIO_HAL_VERSION_1_5; } catch (NoSuchElementException e) { } if (mRadioProxy == null) { try { mRadioProxy = android.hardware.radio.V1_4.IRadio.getService( HIDL_SERVICE_NAME[mPhoneId], true); mRadioVersion = RADIO_HAL_VERSION_1_4; } catch (NoSuchElementException e) { } } if (mRadioProxy == null) { try { mRadioProxy = android.hardware.radio.V1_3.IRadio.getService( HIDL_SERVICE_NAME[mPhoneId], true); mRadioVersion = RADIO_HAL_VERSION_1_3; } catch (NoSuchElementException e) { } } if (mRadioProxy == null) { try { mRadioProxy = android.hardware.radio.V1_2.IRadio.getService( HIDL_SERVICE_NAME[mPhoneId], true); mRadioVersion = RADIO_HAL_VERSION_1_2; } catch (NoSuchElementException e) { } } if (mRadioProxy == null) { try { mRadioProxy = android.hardware.radio.V1_1.IRadio.getService( HIDL_SERVICE_NAME[mPhoneId], true); mRadioVersion = RADIO_HAL_VERSION_1_1; } catch (NoSuchElementException e) { } } if (mRadioProxy == null) { try { mRadioProxy = android.hardware.radio.V1_0.IRadio.getService( HIDL_SERVICE_NAME[mPhoneId], true); mRadioVersion = RADIO_HAL_VERSION_1_0; } catch (NoSuchElementException e) { } } if (mRadioProxy != null) { mRadioProxy.linkToDeath(mRadioProxyDeathRecipient, mRadioProxyCookie.incrementAndGet()); mRadioProxy.setResponseFunctions(mRadioResponse, mRadioIndication); } else { mDisabledRadioServices.add(mPhoneId); riljLoge("getRadioProxy: mRadioProxy for " + HIDL_SERVICE_NAME[mPhoneId] + " is disabled"); } } } catch (RemoteException e) { mRadioProxy = null; riljLoge("RadioProxy getService/setResponseFunctions: " + e); } if (mRadioProxy == null) { // getService() is a blocking call, so this should never happen riljLoge("getRadioProxy: mRadioProxy == null"); if (result != null) { AsyncResult.forMessage(result, null, CommandException.fromRilErrno(RADIO_NOT_AVAILABLE)); result.sendToTarget(); } } return mRadioProxy; }frameworks/opt/telephony/src/java/com/android/internal/telephony/TelephonyDevController.java/** * each RIL call this interface to register/unregister the unsolicited hardware * configuration callback data it can provide. */ public static void registerRIL(CommandsInterface cmdsIf) { /* get the current configuration from this ril... */ cmdsIf.getHardwareConfig(sRilHardwareConfig); /* ... process it ... */ if (sRilHardwareConfig != null) { AsyncResult ar = (AsyncResult) sRilHardwareConfig.obj; if (ar.exception == null) { handleGetHardwareConfigChanged(ar); } } /* and register for async device configuration change. */ cmdsIf.registerForHardwareConfigChanged(sTelephonyDevController, EVENT_HARDWARE_CONFIG_CHANGED, null); } public static void unregisterRIL(CommandsInterface cmdsIf) { cmdsIf.unregisterForHardwareConfigChanged(sTelephonyDevController); }跟踪代码找到最终卡住的地方是在创建RIL的时候同时, 从Log中可以看出一些与RIL相关的LOG.01:48:48.154 1880-1880 chatty com.android.phone I uid=1001(radio) com.android.phone expire 4 lines 01:48:48.160 331-339 RIL RILU pid-331 E cannot find ttyname for AT Port 01:48:48.161 331-339 RIL RILC D USB can't find at device 01:48:51.161 331-339 RIL RILU D find_pci_device is 0 01:48:51.170 331-339 RIL RILU E cannot find ttyname for AT Port 01:48:51.171 331-339 RIL RILC D USB can't find at device 01:48:52.168 1880-1880 HidlS...ment com.android.phone W Waited one second for android.hardware.radio@1.1::IRadio/slot1 01:48:53.172 1880-1880 HidlS...ment W Waited one second for android.hardware.radio@1.1::IRadio/slot1 01:48:54.172 331-339 RIL RILU pid-331 D find_pci_device is 0显然, 这个找不到4G, 所以自然而然地RIL初始化失败了如果接上4G模块, 则不会出现这个问题在长时间等待初始化后, 伴随而来的还有来自于com.android.phone的ANR报错.2022-09-16 07:18:14.975 426-1802/system_process E/ActivityManager: ANR in com.android.phone PID: 873 Reason: Broadcast of Intent { act=android.intent.action.BOOT_COMPLETED flg=0x89000010 cmp=com.android.phone/.vvm.VvmSimStateTracker (has extras) } Load: 0.0 / 0.0 / 0.0 ----- Output from /proc/pressure/memory ----- some avg10=0.00 avg60=0.00 avg300=0.00 total=0 full avg10=0.00 avg60=0.00 avg300=0.00 total=0 ----- End output from /proc/pressure/memory ----- CPU usage from 64519ms to 0ms ago (2022-09-16 07:17:10.274 to 2022-09-16 07:18:14.793): 10% 426/system_server: 7.9% user + 2.6% kernel / faults: 15491 minor 133 major 3.5% 579/com.android.systemui: 2.9% user + 0.5% kernel / faults: 8380 minor 1 major 1.6% 174/surfaceflinger: 1% user + 0.6% kernel / faults: 550 minor 1.5% 1124/com.google.android.inputmethod.pinyin: 1.2% user + 0.2% kernel / faults: 5726 minor 39 major 1.4% 331/adbd: 0.4% user + 1% kernel / faults: 8283 minor 1.3% 146/rknn_server: 0.1% user + 1.2% kernel 0.5% 224/android.hardware.graphics.composer@2.1-service: 0.2% user + 0.3% kernel / faults: 31 minor 0.5% 138/logd: 0.1% user + 0.3% kernel / faults: 21 minor 0.4% 340/installd: 0.3% user + 0.1% kernel / faults: 140 minor 0.4% 246/zygote64: 0% user + 0.3% kernel / faults: 2679 minor 0.3% 329/rild: 0% user + 0.3% kernel 0.3% 7/kworker/u8:0-flush-179:0: 0% user + 0.3% kernel / faults: 1137 minor 0.2% 50/cfinteractive: 0% user + 0.2% kernel 0.2% 286/audioserver: 0.1% user + 0.1% kernel / faults: 125 minor 0.2% 346/mediaserver: 0.1% user + 0.1% kernel / faults: 346 minor 0.2% 141/hwservicemanager: 0% user + 0.1% kernel / faults: 192 minor 0.2% 387/media.swcodec: 0.1% user + 0% kernel / faults: 136 minor 0.2% 870/logcat: 0% user + 0.1% kernel 0.2% 949/com.android.launcher3: 0.1% user + 0% kernel / faults: 537 minor 0.2% 1/init: 0% user + 0.1% kernel / faults: 39 minor 0.1% 81/kworker/0:1H-mmc_complete: 0% user + 0.1% kernel 0.1% 111/kworker/2:2H-kblockd: 0% user + 0.1% kernel 0.1% 262/android.hardware.audio.service: 0% user + 0.1% kernel / faults: 37 minor 0.1% 230/kworker/u8:3-devfreq_wq: 0% user + 0.1% kernel / faults: 770 minor 0.1% 393/irq/77-dwc3: 0% user + 0.1% kernel 0.1% 873/com.android.phone: 0% user + 0% kernel / faults: 14 minor 0.1% 244/statsd: 0% user + 0% kernel / faults: 6 minor 0.1% 896/com.android.settings: 0.1% user + 0% kernel / faults: 420 minor 1 major 0.1% 95/kworker/1:1H-kblockd: 0% user + 0.1% kernel 0.1% 231/kworker/0:3H-mmc_complete: 0% user + 0.1% kernel 0.1% 917/android.ext.services: 0.1% user + 0% kernel / faults: 630 minor 0.1% 46/kworker/2:1-events_freezable: 0% user + 0.1% kernel 0.1% 80/kworker/3:1H-kblockd: 0% user + 0.1% kernel 0.1% 140/servicemanager: 0% user + 0% kernel 0.1% 1102/com.android.deskclock: 0% user + 0% kernel / faults: 503 minor 0% 229/kworker/u8:2: 0% user + 0% kernel / faults: 350 minor 0% 425/kworker/u9:2-kbase_pm_poweroff_wait: 0% user + 0% kernel 0% 10/rcu_preempt: 0% user + 0% kernel 0% 139/lmkd: 0% user + 0% kernel 0% 216/android.hardware.graphics.allocator@4.0-service: 0% user + 0% kernel / faults: 191 minor 0% 481/kworker/u9:3-blk_crypto_wq: 0% user + 0% kernel 0% 78/ion_system_heap: 0% user + 0% kernel 0% 105/kworker/1:2H-kblockd: 0% user + 0% kernel 0% 124/kworker/3:2-events_power_efficient: 0% user + 0% kernel 0% 190/f2fs_discard-25: 0% user + 0% kernel 0% 270/android.hardware.health@2.1-service: 0% user + 0% kernel 0% 977/com.hsdz.systemcontroler:shellservice: 0% user + 0% kernel / faults: 163 minor 0% 11/rcu_sched: 0% user + 0% kernel 0% 14/kworker/0:1-kdmflush: 0% user + 0% kernel 0% 45/kconsole: 0% user + 0% kernel 0% 131/kworker/1:2-kdmflush: 0% user + 0% kernel 0% 148/vold: 0% user + 0% kernel / faults: 87 minor 0% 172/android.system.suspend@1.0-service: 0% user + 0% kernel 0% 280/android.hardware.power-service.rockchip: 0% user + 0% kernel 0% 342/media.extractor: 0% user + 0% kernel 0% 822/com.android.se: 0% user + 0% kernel / faults: 10 minor解决 可以从packages/services/Telephony着手, 将PhoneApp中的代码移到Service中去执行, 这样改了之后, 会产生什么影响, 需要做更多验证, 至少目前测试来说, 4G部分功能及开机广播功能都正常.
平台 Android11 + RK3566 + AndroidStudioAndroid 权限的变化, 几乎每个版本的SDK都会有, 其中最大的一次是在6.0时, 增加的动态权限申请读写存储的权限也几经更迭, 对开发人员来说, 越来越难.比如, 本文所要讨论的:允许管理所有文件如何出现上面两种不同的文件权限选项?1.首先是 targetSdkVersion 大于等于 30. (build.gradle)2.当声明了 READ_EXTERNAL_STORAGE和WRITE_EXTERNAL_STORAGE仅允许访问媒体文件3.当声明了 MANAGE_EXTERNAL_STORAGE 会增加允许管理所有文件4.targetSdkVersion <= 28 时, 只有允许管理所有文件和 拒绝 选项.编写测试代码执行以下动作:1.申请权限2.获取内部存储下的1.txt文件3.若文件存在, 删除并输出结果4.尝试写入文件5.读写失败:2022-09-03 07:25:11.067 1262-10770/com.android.providers.media.module E/MediaProvider: insertFileIfNecessary failed java.lang.IllegalArgumentException: Primary directory null not allowed for content://media/external_primary/file; allowed directories are [Download, Documents] at com.android.providers.media.MediaProvider.ensureFileColumns(MediaProvider.java:2923) at com.android.providers.media.MediaProvider.ensureUniqueFileColumns(MediaProvider.java:2588) at com.android.providers.media.MediaProvider.insertFile(MediaProvider.java:3282) at com.android.providers.media.MediaProvider.insertInternal(MediaProvider.java:3826) at com.android.providers.media.MediaProvider.insert(MediaProvider.java:3537) at com.android.providers.media.MediaProvider.insertFileForFuse(MediaProvider.java:7187) at com.android.providers.media.MediaProvider.insertFileIfNecessaryForFuse(MediaProvider.java:7281) 2022-09-03 07:25:11.068 10710-10710/com.android.apitester W/System.err: java.io.FileNotFoundException: /storage/emulated/0/1.txt: open failed: EPERM (Operation not permitted) 2022-09-03 07:25:11.068 10710-10710/com.android.apitester W/System.err: at libcore.io.IoBridge.open(IoBridge.java:492) 2022-09-03 07:25:11.068 10710-10710/com.android.apitester W/System.err: at java.io.FileOutputStream.<init>(FileOutputStream.java:236) 2022-09-03 07:25:11.068 10710-10710/com.android.apitester W/System.err: at java.io.FileOutputStream.<init>(FileOutputStream.java:186) 2022-09-03 07:25:11.069 10710-10710/com.android.apitester W/System.err: at com.android.apitester.PermissionTest.fileOperation(PermissionTest.java:124) 2022-09-03 07:25:11.069 10710-10710/com.android.apitester W/System.err: at com.android.apitester.PermissionTest.onClick(PermissionTest.java:50) 2022-09-03 07:25:11.069 10710-10710/com.android.apitester W/System.err: at android.view.View.performClick(View.java:7448) 2022-09-03 07:25:11.069 10710-10710/com.android.apitester W/System.err: at android.view.View.performClickInternal(View.java:7425) 2022-09-03 07:25:11.069 10710-10710/com.android.apitester W/System.err: at android.view.View.access$3600(View.java:810) 2022-09-03 07:25:11.070 10710-10710/com.android.apitester W/System.err: at android.view.View$PerformClick.run(View.java:28310) 2022-09-03 07:25:11.070 10710-10710/com.android.apitester W/System.err: at android.os.Handler.handleCallback(Handler.java:938) 2022-09-03 07:25:11.070 10710-10710/com.android.apitester W/System.err: at android.os.Handler.dispatchMessage(Handler.java:99) 2022-09-03 07:25:11.070 10710-10710/com.android.apitester W/System.err: at android.os.Looper.loop(Looper.java:223) 2022-09-03 07:25:11.070 10710-10710/com.android.apitester W/System.err: at android.app.ActivityThread.main(ActivityThread.java:7664) 2022-09-03 07:25:11.070 10710-10710/com.android.apitester W/System.err: at java.lang.reflect.Method.invoke(Native Method) 2022-09-03 07:25:11.071 10710-10710/com.android.apitester W/System.err: at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:592) 2022-09-03 07:25:11.071 10710-10710/com.android.apitester W/System.err: at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:947) 2022-09-03 07:25:11.071 10710-10710/com.android.apitester W/System.err: Caused by: android.system.ErrnoException: open failed: EPERM (Operation not permitted) 2022-09-03 07:25:11.071 10710-10710/com.android.apitester W/System.err: at libcore.io.Linux.open(Native Method) 2022-09-03 07:25:11.072 10710-10710/com.android.apitester W/System.err: at libcore.io.ForwardingOs.open(ForwardingOs.java:166) 2022-09-03 07:25:11.072 10710-10710/com.android.apitester W/System.err: at libcore.io.BlockGuardOs.open(BlockGuardOs.java:254) 2022-09-03 07:25:11.072 10710-10710/com.android.apitester W/System.err: at libcore.io.ForwardingOs.open(ForwardingOs.java:166) 2022-09-03 07:25:11.072 10710-10710/com.android.apitester W/System.err: at android.app.ActivityThread$AndroidOs.open(ActivityThread.java:7550) 2022-09-03 07:25:11.072 10710-10710/com.android.apitester W/System.err: at libcore.io.IoBridge.open(IoBridge.java:478) 2022-09-03 07:25:11.072 10710-10710/com.android.apitester W/System.err: ... 15 more 2022-09-03 07:25:11.073 10710-10710/com.android.apitester E/PermissionTest: write /storage/emulated/0/1.txt failed 2022-09-03 07:25:11.094 1262-1367/com.android.providers.media.module I/MediaProvider: Deleted 1 items on external_primary due to com.android.apitester 2022-09-03 07:25:11.097 10710-10710/com.android.apitester D/PermissionTest: delete /storage/emulated/0/Download/1.txt success 2022-09-03 07:25:11.124 10710-10710/com.android.apitester D/PermissionTest: write /storage/emulated/0/Download/1.txt success 2022-09-03 07:25:11.131 10710-10710/com.android.apitester D/PermissionTest: delete /storage/emulated/0/Android/data/com.android.apitester/files/Documents/1.txt success 2022-09-03 07:25:11.137 10710-10710/com.android.apitester D/PermissionTest: write /storage/emulated/0/Android/data/com.android.apitester/files/Documents/1.txt success结果(FAILED:失败, SUCCESS成功):源码中权限窗口packages/apps/PermissionController/START u0 {act=android.intent.action.MANAGE_APP_PERMISSIONS cmp=com.android.permissioncontroller/.permission.ui.ManagePermissionsActivity (has extras)} from uid 1000布局文件packages/apps/PermissionController/res/navigation/nav_graph.xmlpackages/apps/PermissionController/res/layout/app_permission.xml相关源码packages/apps/PermissionController/src/com/android/permissioncontroller/permission/ui/ManagePermissionsActivity.javapackages/apps/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/AppPermissionFragment.java请求权限的交互UI显示内容的判定加载应用存储权限packages/apps/PermissionController/src/com/android/permissioncontroller/permission/data/FullStoragePermissionAppsLiveData.ktdata class FullStoragePackageState( val packageName: String, val user: UserHandle, val isLegacy: Boolean, val isGranted: Boolean ) override suspend fun loadDataAndPostValue(job: Job) { val storagePackages = standardPermGroupsPackagesLiveData.value?.get(STORAGE) ?: return val appOpsManager = app.getSystemService(AppOpsManager::class.java) ?: return val fullStoragePackages = mutableListOf<FullStoragePackageState>() for ((user, packageInfoList) in AllPackageInfosLiveData.value ?: emptyMap()) { val userPackages = packageInfoList.filter { storagePackages.contains(it.packageName to user) || it.requestedPermissions.contains(MANAGE_EXTERNAL_STORAGE) } for (packageInfo in userPackages) { val sdk = packageInfo.targetSdkVersion if (sdk < Build.VERSION_CODES.P) {//targetSdkVersion 28 fullStoragePackages.add(FullStoragePackageState(packageInfo.packageName, user, isLegacy = true, isGranted = true)) continue } else if (sdk <= Build.VERSION_CODES.Q &&//targetSdkVersion 29 appOpsManager.unsafeCheckOpNoThrow(OPSTR_LEGACY_STORAGE, packageInfo.uid, packageInfo.packageName) == MODE_ALLOWED) { fullStoragePackages.add(FullStoragePackageState(packageInfo.packageName, user, isLegacy = true, isGranted = true)) continue } //存在MANAGE_EXTERNAL_STORAGE if (MANAGE_EXTERNAL_STORAGE in packageInfo.requestedPermissions) { val mode = appOpsManager.unsafeCheckOpNoThrow(OPSTR_MANAGE_EXTERNAL_STORAGE, packageInfo.uid, packageInfo.packageName) val granted = mode == MODE_ALLOWED || mode == MODE_FOREGROUND || (mode == MODE_DEFAULT && MANAGE_EXTERNAL_STORAGE in packageInfo.grantedPermissions) fullStoragePackages.add(FullStoragePackageState(packageInfo.packageName, user, isLegacy = false, isGranted = granted)) } } } postValue(fullStoragePackages) }isLegacy表示是否是旧的权限模式, UI会根据上面的代码进行逻辑运算并更新对应的UI信息.packages/apps/PermissionController/src/com/android/permissioncontroller/permission/ui/model/AppPermissionViewModel.ktoverride fun onUpdate() { val group = appPermGroupLiveData.value ?: return val admin = RestrictedLockUtils.getProfileOrDeviceOwner(app, user) val couldPackageHaveFgCapabilities = foregroundCapableType != Utils.ForegroundCapableType.NONE val allowedState = ButtonState() val allowedAlwaysState = ButtonState() val allowedForegroundState = ButtonState() val askOneTimeState = ButtonState() val askState = ButtonState() val deniedState = ButtonState() val deniedForegroundState = ButtonState() // when bg is fixed as granted and fg is flex askState.isShown = Utils.supportsOneTimeGrant(permGroupName) && !(group.foreground.isGranted && group.isOneTime) deniedState.isShown = true if (group.hasPermWithBackgroundMode) { // Background / Foreground / Deny case allowedForegroundState.isShown = true if (group.hasBackgroundGroup) { allowedAlwaysState.isShown = true } allowedAlwaysState.isChecked = group.background.isGranted && group.foreground.isGranted allowedForegroundState.isChecked = group.foreground.isGranted && !group.background.isGranted && !group.isOneTime askState.isChecked = !group.foreground.isGranted && group.isOneTime askOneTimeState.isChecked = group.foreground.isGranted && group.isOneTime askOneTimeState.isShown = askOneTimeState.isChecked deniedState.isChecked = !group.foreground.isGranted && !group.isOneTime var detailId = 0 if (applyFixToForegroundBackground(group, group.foreground.isSystemFixed, group.background.isSystemFixed, allowedAlwaysState, allowedForegroundState, askState, deniedState, deniedForegroundState) || applyFixToForegroundBackground(group, group.foreground.isPolicyFixed, group.background.isPolicyFixed, allowedAlwaysState, allowedForegroundState, askState, deniedState, deniedForegroundState)) { showAdminSupportLiveData.value = admin detailId = getDetailResIdForFixedByPolicyPermissionGroup(group, admin != null) if (detailId != 0) { detailResIdLiveData.value = detailId to null } } else if (Utils.areGroupPermissionsIndividuallyControlled(app, permGroupName)) { val detailPair = getIndividualPermissionDetailResId(group) detailId = detailPair.first detailResIdLiveData.value = detailId to detailPair.second } if (couldPackageHaveFgCapabilities) { // Correct the UI in case the app can access bg location with only fg perm allowedAlwaysState.isShown = true allowedAlwaysState.isChecked = allowedAlwaysState.isChecked || allowedForegroundState.isChecked // Should be enabled && is denied enabled for the user to be able to switch to. allowedAlwaysState.isEnabled = ((allowedAlwaysState.isEnabled && allowedAlwaysState.isShown) || allowedForegroundState.isEnabled) && ((deniedState.isEnabled && deniedState.isShown) || (deniedForegroundState.isEnabled && deniedForegroundState.isShown)) allowedForegroundState.isChecked = false allowedForegroundState.isEnabled = false deniedState.isChecked = deniedState.isChecked || askState.isChecked deniedForegroundState.isChecked = deniedState.isChecked askState.isEnabled = false if (detailId == 0) { detailId = getForegroundCapableDetailResId(foregroundCapableType) if (detailId != 0) { detailResIdLiveData.value = detailId to null } } } } else { // Allow / Deny case allowedState.isShown = true allowedState.isChecked = group.foreground.isGranted askState.isChecked = !group.foreground.isGranted && group.isOneTime askOneTimeState.isChecked = group.foreground.isGranted && group.isOneTime askOneTimeState.isShown = askOneTimeState.isChecked deniedState.isChecked = !group.foreground.isGranted && !group.isOneTime var detailId = 0 if (group.foreground.isPolicyFixed || group.foreground.isSystemFixed) { allowedState.isEnabled = false askState.isEnabled = false deniedState.isEnabled = false showAdminSupportLiveData.value = admin val detailId = getDetailResIdForFixedByPolicyPermissionGroup(group, admin != null) if (detailId != 0) { detailResIdLiveData.value = detailId to null } } if (isForegroundGroupSpecialCase(permGroupName)) { allowedForegroundState.isShown = true allowedState.isShown = false allowedForegroundState.isChecked = allowedState.isChecked allowedForegroundState.isEnabled = allowedState.isEnabled if (couldPackageHaveFgCapabilities || (Utils.isEmergencyApp(app, packageName) && isMicrophone(permGroupName))) { allowedAlwaysState.isShown = true allowedAlwaysState.isChecked = allowedForegroundState.isChecked allowedAlwaysState.isEnabled = allowedForegroundState.isEnabled allowedForegroundState.isChecked = false allowedForegroundState.isEnabled = false deniedState.isChecked = deniedState.isChecked || askState.isChecked askState.isEnabled = false if (detailId == 0) { detailId = getForegroundCapableDetailResId(foregroundCapableType) if (detailId != 0) { detailResIdLiveData.value = detailId to null } } } } } if (group.packageInfo.targetSdkVersion < Build.VERSION_CODES.M) { // Pre-M app's can't ask for runtime permissions askState.isShown = false deniedState.isChecked = askState.isChecked || deniedState.isChecked deniedForegroundState.isChecked = askState.isChecked || deniedForegroundState.isChecked } val storageState = fullStorageStateLiveData.value if (isStorage && storageState?.isLegacy != true) { val allowedAllFilesState = allowedAlwaysState val allowedMediaOnlyState = allowedForegroundState if (storageState != null) { // Set up the tri state permission for storage allowedAllFilesState.isEnabled = allowedState.isEnabled allowedAllFilesState.isShown = true if (storageState.isGranted) { allowedAllFilesState.isChecked = true deniedState.isChecked = false } } else { allowedAllFilesState.isEnabled = false allowedAllFilesState.isShown = false } allowedMediaOnlyState.isShown = true allowedMediaOnlyState.isEnabled = allowedState.isEnabled allowedMediaOnlyState.isChecked = allowedState.isChecked && storageState?.isGranted != true allowedState.isChecked = false allowedState.isShown = false } value = mapOf(ALLOW to allowedState, ALLOW_ALWAYS to allowedAlwaysState, ALLOW_FOREGROUND to allowedForegroundState, ASK_ONCE to askOneTimeState, ASK to askState, DENY to deniedState, DENY_FOREGROUND to deniedForegroundState) } }权限请求当targetSdkVersion设置为高版本后, 下面的权限请求代码, 只能申请到仅允许访问媒体文件String[] perms = { //"android.permission.MANAGE_EXTERNAL_STORAGE", Manifest.permission.MANAGE_EXTERNAL_STORAGE, Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE, }; requestPermissions(perms, 0x01);实际上, MANAGE_EXTERNAL_STORAGE现传统的读写权限有很大的区别, 它与浮窗的权限类似, 由AppOpsService进行管理, 上面的代码, 不是能直接向AppOpsService申请权限.开发者可以借助三方工具实现权限请求一般会通过调起系统的授权窗口, 引导用户操作授权:1.方法 一设置 > 应用和通知 > 高级 特殊应用权限 > 所有文件访问权限 > App名称 > 授予所有文件管权限2.方法 二 (实际去到了PermissionController)设置 > 应用和通知 > 所有应用 > App名称 > 权限 > 文件和媒体 > 允许管理所有文件//方法1 START u0 {act=android.settings.MANAGE_APP_ALL_FILES_ACCESS_PERMISSION dat=package:com.android.apitester cmp=com.android.settings/.Settings$AppManageExternalStorageActivity} 方法2 START u0 {act=android.intent.action.MANAGE_APP_PERMISSIONS cmp=com.android.permissioncontroller/.permission.ui.ManagePermissionsActivity (has extras)} from uid 1000这里不作细述.对于XXPermissions试了下, 有两点不习惯的地方:1.要求支持android.support.v4.app.FragmentApiTester/src/main/java/com/android/apitester/PermissionTest.java:78: error: cannot access Fragment XXPermissions.with(this) ^ class file for android.support.v4.app.Fragment not found //所以还得增加依赖包 implementation 'com.android.support:appcompat-v7:27.1.1'2.异常Caused by: java.lang.IllegalArgumentException: If you have applied for MANAGE_EXTERNAL_STORAGE permissions, do not apply for the READ_EXTERNAL_STORAGE and WRITE_EXTERNAL_STORAGE permissions at com.hjq.permissions.PermissionChecker.optimizeDeprecatedPermission(PermissionChecker.java:239) at com.hjq.permissions.XXPermissions.request(XXPermissions.java:167) at com.android.apitester.PermissionTest.onCreate(PermissionTest.java:34) at android.app.Activity.performCreate(Activity.java:8022) at android.app.Activity.performCreate(Activity.java:8006) at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1309) at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3404) at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3595) at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:85) at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135) at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95) at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2066) at android.os.Handler.dispatchMessage(Handler.java:106) at android.os.Looper.loop(Looper.java:223) at android.app.ActivityThread.main(ActivityThread.java:7664) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:592) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:947)参考1.Android 11 中的存储机制更新2.分区存储Android权限适配android grantRuntimePermission 详解XXPermissions
平台 RK3566 + Android 11概述 替换默认主界面, 更换为指定第三方Launcher后, 点击导航栏的RECENT键无效. 究其原因在于, 在旧版本SDK上, 删除Launcher3并不会影响RECENT的功能 , 而在新的SDK上, RECENT功能集成于Launcher3目录下, 删除 Launcher3后, 导致SystemUI调用对应的RECENT界面启动的服务失败.过程疏理frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java@Override public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); mNavigationBarView = (NavigationBarView) view; final Display display = view.getDisplay(); // It may not have display when running unit test. if (display != null) { mDisplayId = display.getDisplayId(); mIsOnDefaultDisplay = mDisplayId == Display.DEFAULT_DISPLAY; } mNavigationBarView.setComponents(mStatusBarLazy.get().getPanelController()); mNavigationBarView.setDisabledFlags(mDisabledFlags1); mNavigationBarView.setOnVerticalChangedListener(this::onVerticalChanged); mNavigationBarView.setOnTouchListener(this::onNavigationTouch); if (savedInstanceState != null) { mNavigationBarView.getLightTransitionsController().restoreState(savedInstanceState); } mNavigationBarView.setNavigationIconHints(mNavigationIconHints); mNavigationBarView.setWindowVisible(isNavBarWindowVisible()); prepareNavigationBarView(); } private void prepareNavigationBarView() { mNavigationBarView.reorient(); ButtonDispatcher recentsButton = mNavigationBarView.getRecentsButton(); recentsButton.setOnClickListener(this::onRecentsClick); recentsButton.setOnTouchListener(this::onRecentsTouch); recentsButton.setLongClickable(true); recentsButton.setOnLongClickListener(this::onLongPressBackRecents); } private void onRecentsClick(View v) { if (LatencyTracker.isEnabled(getContext())) { LatencyTracker.getInstance(getContext()).onActionStart( LatencyTracker.ACTION_TOGGLE_RECENTS); } mStatusBarLazy.get().awakenDreams(); mCommandQueue.toggleRecentApps(); }frameworks/base/packages/SystemUI/src/com/android/systemui/recents/Recents.java@Override public void toggleRecentApps() { // Ensure the device has been provisioned before allowing the user to interact with // recents if (!isUserSetup()) { return; } mImpl.toggleRecentApps(); }frameworks/base/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyRecentsImpl.java@Override public void toggleRecentApps() { Log.d(TAG, "toggleRecentApps"); // If connected to launcher service, let it handle the toggle logic IOverviewProxy overviewProxy = mOverviewProxyService.getProxy(); if (overviewProxy != null) { final Runnable toggleRecents = () -> { try { if (mOverviewProxyService.getProxy() != null) { mOverviewProxyService.getProxy().onOverviewToggle(); mOverviewProxyService.notifyToggleRecentApps(); } } catch (RemoteException e) { Log.e(TAG, "Cannot send toggle recents through proxy service.", e); } }; // Preload only if device for current user is unlocked if (mStatusBarLazy != null && mStatusBarLazy.get().isKeyguardShowing()) { mStatusBarLazy.get().executeRunnableDismissingKeyguard(() -> { // Flush trustmanager before checking device locked per user mTrustManager.reportKeyguardShowingChanged(); mHandler.post(toggleRecents); }, null, true /* dismissShade */, false /* afterKeyguardGone */, true /* deferred */); } else { toggleRecents.run(); } return; } else { // Do nothing } }重点看下overviewProxyframeworks/base/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.javaprivate static final String ACTION_QUICKSTEP = "android.intent.action.QUICKSTEP_SERVICE"; @SuppressWarnings("OptionalUsedAsFieldOrParameterType") @Inject public OverviewProxyService(Context context, CommandQueue commandQueue, NavigationBarController navBarController, NavigationModeController navModeController, NotificationShadeWindowController statusBarWinController, SysUiState sysUiState, PipUI pipUI, Optional<Divider> dividerOptional, Optional<Lazy<StatusBar>> statusBarOptionalLazy, BroadcastDispatcher broadcastDispatcher) { super(broadcastDispatcher); mContext = context; mPipUI = pipUI; mStatusBarOptionalLazy = statusBarOptionalLazy; mHandler = new Handler(); mNavBarController = navBarController; mStatusBarWinController = statusBarWinController; mConnectionBackoffAttempts = 0; mDividerOptional = dividerOptional; //frameworks/base/core/res/res/values/config.xml // <string name="config_recentsComponentName" translatable="false">com.android.launcher3/com.android.quickstep.RecentsActivity</string> mRecentsComponentName = ComponentName.unflattenFromString(context.getString( com.android.internal.R.string.config_recentsComponentName)); mQuickStepIntent = new Intent(ACTION_QUICKSTEP) } //绑定服务 private void internalConnectToCurrentUser() { //.............. Intent launcherServiceIntent = new Intent(ACTION_QUICKSTEP) .setPackage(mRecentsComponentName.getPackageName()); try { mBound = mContext.bindServiceAsUser(launcherServiceIntent, mOverviewServiceConnection, Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE_WHILE_AWAKE, UserHandle.of(getCurrentUserId())); } catch (SecurityException e) { Log.e(TAG_OPS, "Unable to bind because of security error", e); } //..... } //绑定成功 private final ServiceConnection mOverviewServiceConnection = new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) { //......... mOverviewProxy = IOverviewProxy.Stub.asInterface(service); } //由上面OverviewProxyRecentsImpl 调用 public IOverviewProxy getProxy() { return mOverviewProxy; }近期任务UI的实现有别与旧版本的SDK, 有frameworks/base/packages/SystemUI改到了packages/apps/Launcher3/quicksteppackages/apps/Launcher3/quickstep/AndroidManifest.xml <service android:name="com.android.quickstep.TouchInteractionService" android:permission="android.permission.STATUS_BAR_SERVICE" android:directBootAware="true" > <intent-filter> <action android:name="android.intent.action.QUICKSTEP_SERVICE" /> </intent-filter> </service>为了使用默认第三方Launcher, 需要注释掉quickstep自带的Launcherpackages/apps/Launcher3/quickstep/AndroidManifest-launcher.xml <activity android:name="com.android.launcher3.uioverrides.QuickstepLauncher" android:launchMode="singleTask" android:clearTaskOnLaunch="true" android:stateNotNeeded="true" android:windowSoftInputMode="adjustPan" android:screenOrientation="unspecified" android:configChanges="keyboard|keyboardHidden|mcc|mnc|navigation|orientation|screenSize|screenLayout|smallestScreenSize" android:resizeableActivity="true" android:resumeWhilePausing="true" android:taskAffinity="" android:enabled="true"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <!--category android:name="android.intent.category.HOME" /--> <category android:name="android.intent.category.DEFAULT" /> <!--category android:name="android.intent.category.MONKEY"/--> <category android:name="android.intent.category.LAUNCHER_APP" /> </intent-filter> <meta-data android:name="com.android.launcher3.grid.control" android:value="${packageName}.grid_control" /> </activity>开机奔溃2022-07-10 04:01:50.179 1472-1472/com.android.launcher3 E/AndroidRuntime: FATAL EXCEPTION: main Process: com.android.launcher3, PID: 1472 java.lang.RuntimeException: Unable to create service com.android.quickstep.TouchInteractionService: java.lang.NullPointerException: Attempt to read from field 'android.content.pm.ActivityInfo android.content.pm.ResolveInfo.activityInfo' on a null object reference at android.app.ActivityThread.handleCreateService(ActivityThread.java:4198) at android.app.ActivityThread.access$1500(ActivityThread.java:237) at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1932) at android.os.Handler.dispatchMessage(Handler.java:106) at android.os.Looper.loop(Looper.java:223) at android.app.ActivityThread.main(ActivityThread.java:7664) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:592) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:947) Caused by: java.lang.NullPointerException: Attempt to read from field 'android.content.pm.ActivityInfo android.content.pm.ResolveInfo.activityInfo' on a null object reference at com.android.quickstep.OverviewComponentObserver.<init>(OverviewComponentObserver.java:82) at com.android.quickstep.TouchInteractionService.onUserUnlocked(TouchInteractionService.java:345) at com.android.quickstep.-$$Lambda$6M6xH0rMyGjroOocJ2F5KYabvuw.run(Unknown Source:2) at com.android.quickstep.RecentsAnimationDeviceState.runOnUserUnlocked(RecentsAnimationDeviceState.java:272) at com.android.quickstep.TouchInteractionService.onCreate(TouchInteractionService.java:301) at android.app.ActivityThread.handleCreateService(ActivityThread.java:4186) at android.app.ActivityThread.access$1500(ActivityThread.java:237) at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1932) at android.os.Handler.dispatchMessage(Handler.java:106) at android.os.Looper.loop(Looper.java:223) at android.app.ActivityThread.main(ActivityThread.java:7664) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:592) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:947)packages/apps/Launcher3/quickstep/src/com/android/quickstep/OverviewComponentObserver.javapublic OverviewComponentObserver(Context context, RecentsAnimationDeviceState deviceState) { mContext = context; mDeviceState = deviceState; mCurrentHomeIntent = new Intent(Intent.ACTION_MAIN) .addCategory(Intent.CATEGORY_HOME) .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); //异常位置: 由于前面注释掉了自带Launcher导致, 将mContext.getPackageName 替换成 三方Launcher的包名可解决. mMyHomeIntent = new Intent(mCurrentHomeIntent).setPackage(/*mContext.getPackageName()*/"com.android.launcherX"); ResolveInfo info = context.getPackageManager().resolveActivity(mMyHomeIntent, 0); ComponentName myHomeComponent = new ComponentName(/*mContext.getPackageName()*/"com.android.launcherX", info.activityInfo.name); mMyHomeIntent.setComponent(myHomeComponent); mConfigChangesMap.append(myHomeComponent.hashCode(), info.activityInfo.configChanges); ComponentName fallbackComponent = new ComponentName(mContext, RecentsActivity.class); mFallbackIntent = new Intent(Intent.ACTION_MAIN) .addCategory(Intent.CATEGORY_DEFAULT) .setComponent(fallbackComponent) .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); try { ActivityInfo fallbackInfo = context.getPackageManager().getActivityInfo( mFallbackIntent.getComponent(), 0 /* flags */); mConfigChangesMap.append(fallbackComponent.hashCode(), fallbackInfo.configChanges); } catch (PackageManager.NameNotFoundException ignored) { /* Impossible */ } mContext.registerReceiver(mUserPreferenceChangeReceiver, new IntentFilter(ACTION_PREFERRED_ACTIVITY_CHANGED)); updateOverviewTargets(); }解决奔溃问题后, 点击recent键返回了HOME, 而不是显示RECENT界面:packages/apps/Launcher3/quickstep/src/com/android/quickstep/OverviewComponentObserver.java /** * Update overview intent and {@link BaseActivityInterface} based off the current launcher home * component. */ private void updateOverviewTargets() { ComponentName defaultHome = PackageManagerWrapper.getInstance() .getHomeActivities(new ArrayList<>()); mIsHomeDisabled = mDeviceState.isHomeDisabled(); mIsDefaultHome = Objects.equals(mMyHomeIntent.getComponent(), defaultHome); // Set assistant visibility to 0 from launcher's perspective, ensures any elements that // launcher made invisible become visible again before the new activity control helper // becomes active. if (mActivityInterface != null) { mActivityInterface.onAssistantVisibilityChanged(0.f); } if (SEPARATE_RECENTS_ACTIVITY.get()) { mIsDefaultHome = false; if (defaultHome == null) { defaultHome = mMyHomeIntent.getComponent(); } } //不走if分支, if (false && !mDeviceState.isHomeDisabled() && (defaultHome == null || mIsDefaultHome)) { // User default home is same as out home app. Use Overview integrated in Launcher. mActivityInterface = LauncherActivityInterface.INSTANCE; mIsHomeAndOverviewSame = true; mOverviewIntent = mMyHomeIntent; mCurrentHomeIntent.setComponent(mMyHomeIntent.getComponent()); // Remove any update listener as we don't care about other packages. unregisterOtherHomeAppUpdateReceiver(); } else { // The default home app is a different launcher. Use the fallback Overview instead. mActivityInterface = FallbackActivityInterface.INSTANCE; mIsHomeAndOverviewSame = false; mOverviewIntent = mFallbackIntent; mCurrentHomeIntent.setComponent(defaultHome); // User's default home app can change as a result of package updates of this app (such // as uninstalling the app or removing the "Launcher" feature in an update). // Listen for package updates of this app (and remove any previously attached // package listener). if (defaultHome == null) { unregisterOtherHomeAppUpdateReceiver(); } else if (!defaultHome.getPackageName().equals(mUpdateRegisteredPackage)) { unregisterOtherHomeAppUpdateReceiver(); mUpdateRegisteredPackage = defaultHome.getPackageName(); mContext.registerReceiver(mOtherHomeAppUpdateReceiver, getPackageFilter( mUpdateRegisteredPackage, ACTION_PACKAGE_ADDED, ACTION_PACKAGE_CHANGED, ACTION_PACKAGE_REMOVED)); } } mOverviewChangeListener.accept(mIsHomeAndOverviewSame); }关键在于使mOverviewIntent = mFallbackIntent;由SystemUI调用onOverviewToggle:packages/apps/Launcher3/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java@BinderThread @Override public void onOverviewToggle() { TestLogging.recordEvent(TestProtocol.SEQUENCE_MAIN, "onOverviewToggle"); mOverviewCommandHelper.onOverviewToggle(); }packages/apps/Launcher3/quickstep/recents_ui_overrides/src/com/android/quickstep/OverviewCommandHelper.java@BinderThread public void onOverviewToggle() { // If currently screen pinning, do not enter overview if (mDeviceState.isScreenPinningActive()) { return; } ActivityManagerWrapper.getInstance() .closeSystemWindows(CLOSE_SYSTEM_WINDOWS_REASON_RECENTS); MAIN_EXECUTOR.execute(new RecentsActivityCommand<>()); }MAIN_EXECUTOR 和 LooperExecutorRecentsActivityCommandprivate class RecentsActivityCommand<T extends StatefulActivity<?>> implements Runnable { protected final BaseActivityInterface<?, T> mActivityInterface; //..... private ActivityInitListener mListener; public RecentsActivityCommand() { mActivityInterface = mOverviewComponentObserver.getActivityInterface(); //.... } @Override public void run() { //... // Otherwise, start overview. mListener = mActivityInterface.createActivityInitListener(this::onActivityReady); mListener.registerAndStartActivity(mOverviewComponentObserver.getOverviewIntent(), new RemoteAnimationProvider() { @Override public AnimatorSet createWindowAnimation( RemoteAnimationTargetCompat[] appTargets, RemoteAnimationTargetCompat[] wallpaperTargets) { return RecentsActivityCommand.this.createWindowAnimation(appTargets, wallpaperTargets); } }, mContext, MAIN_EXECUTOR.getHandler(), mAnimationProvider.getRecentsLaunchDuration()); }packages/apps/Launcher3/quickstep/src/com/android/quickstep/OverviewComponentObserver.java/** * Get the current activity control helper for managing interactions to the overview activity. * * @return the current activity control helper */ public BaseActivityInterface getActivityInterface() { return mActivityInterface; }OverviewComponentObserver.mActivityInterface = FallbackActivityInterface.INSTANCE;packages/apps/Launcher3/quickstep/recents_ui_overrides/src/com/android/quickstep/FallbackActivityInterface.javapublic final class FallbackActivityInterface extends BaseActivityInterface<RecentsState, RecentsActivity> { public static final FallbackActivityInterface INSTANCE = new FallbackActivityInterface(); @Override public ActivityInitListener createActivityInitListener( Predicate<Boolean> onInitListener) { return new ActivityInitListener<>((activity, alreadyOnHome) -> onInitListener.test(alreadyOnHome), RecentsActivity.ACTIVITY_TRACKER); }packages/apps/Launcher3/quickstep/src/com/android/quickstep/util/ActivityInitListener.java/** * Starts the given intent with the provided animation. Unlike {@link #register(Intent)}, this * method will not call {@link #init} if the activity already exists, it will only call it when * we get handleIntent() for the provided intent that we're starting. */ public void registerAndStartActivity(Intent intent, RemoteAnimationProvider animProvider, Context context, Handler handler, long duration) { mIsRegistered = true; Bundle options = animProvider.toActivityOptions(handler, duration, context).toBundle(); context.startActivity(addToIntent(new Intent(intent)), options); }最终context.startActivity 其中的Intent是:mOverviewComponentObserver.getOverviewIntent()packages/apps/Launcher3/quickstep/src/com/android/quickstep/OverviewComponentObserver.java /** * Get the current intent for going to the overview activity. * * @return the overview intent */ public Intent getOverviewIntent() { /*参见前面的代码: ComponentName fallbackComponent = new ComponentName(mContext, RecentsActivity.class); mFallbackIntent = new Intent(Intent.ACTION_MAIN) .addCategory(Intent.CATEGORY_DEFAULT) .setComponent(fallbackComponent) .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); */ return mOverviewIntent; }至此RecentsActivity启动完成.模块编译:mmm packages/apps/Launcher3/:Launcher3QuickStep -j4需要注意的是1.原生的Launcher3需要注释掉, 或让它不参与编译.2.近期任务UI的存放目录是在Lauuncher3目录下, 而需要参与编译的模块只有Launcher3QuickStep3.第三方Launcher不能使用com.android.launcher3这个包名, 与上面的模块冲突参考SystemUI之QuickStep探索(常规启动篇)Android11 最近任务Recents功能分析
概述 Android 下, 使用SurfaceView显示摄像头预览, 通常使用的是一个矩形窗口, 如果, 要使用一个圆形窗口呢?先上效果图未打开摄像头打开摄像头实现过程视图布局实现圆形裁剪的方法有很多, 最简单的, 可以在SurfaceView上方增加一个视图遮罩, 挡住不需要显示的区域即可遮罩的方法有一个问题:上图中, 属于ImageView的红色区域也会被遮挡本文中采用的方法是:用一个RelativeLayout包含SurfaceView, 通过裁剪RelativeLayout来实现:@Override protected void dispatchDraw(Canvas canvas) { //裁剪圆型画布,使SurfaceView显示圆形区域图像 canvas.save(); canvas.clipPath(path); super.dispatchDraw(canvas); canvas.restore(); }增加按键位置的拖动功能, 主要是为了解决验证一个问题://设置输入监听, 用于拖动按键位置. btn.setOnTouchListener(new View.OnTouchListener() { float cx, cy, dx, dy; int tx, ty; @Override public boolean onTouch(View v, MotionEvent event) { cx = event.getRawX(); cy = event.getRawY(); switch(event.getAction()){ case MotionEvent.ACTION_DOWN: dx = cx; dy = cy; tx = lpBtn.leftMargin; ty = lpBtn.topMargin; break; case MotionEvent.ACTION_MOVE: lpBtn.leftMargin = (int)(tx + (cx - dx)); lpBtn.topMargin = (int)(ty + (cy - dy)); btn.setLayoutParams(lpBtn); break; case MotionEvent.ACTION_UP: //开始预览 cameraHelper.openCamera(false); cameraHelper.startPreview(null); //必须设置为FALSE //sv.setZOrderOnTop(false); rlRoot.requestLayout(); break; } return false; } });当写完代码开始在设备上运行调试时, 出现了一个奇怪的问题:当系统显示导航栏时, 可以正常显示裁剪后的圆形, 在全屏或隐藏导航栏后, 裁剪失效了:要解决这个问题也简单, 只需要在**XRelativeLayout(rl)**中的SurfaceView上, 覆盖一个控件, 源码中已注释//MUST add view overlay rl.addView(new View(this));当然也可以增加到rlRoot中, 从上面的动图可以看到, 裁剪的有效范围与Button的位置有关.参考代码import android.content.Context; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Path; import android.graphics.PixelFormat; import android.os.Bundle; import android.os.SystemClock; import android.view.MotionEvent; import android.view.SurfaceView; import android.view.View; import android.widget.Button; import android.widget.ImageView; import android.widget.RelativeLayout; import android.app.Activity; public class CameraPreview extends Activity { int cameraId = 1; //根控件 RelativeLayout rlRoot; CameraHelper cameraHelper; SurfaceView sv; RelativeLayoutX rl; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); rlRoot = new RelativeLayout(this); //显示于SurfaceView 下方的ImageView ImageView iv = new ImageView(this); RelativeLayout.LayoutParams lpIv = new RelativeLayout.LayoutParams(UiTools.WRAP_CONTENT, UiTools.WRAP_CONTENT); iv.setScaleType(ImageView.ScaleType.FIT_XY); iv.setImageResource(R.drawable.ic_drawer_product_imgs); iv.setOnTouchListener(new View.OnTouchListener() { float cx, cy, dx, dy; int tx, ty; @Override public boolean onTouch(View v, MotionEvent event) { cx = event.getRawX(); cy = event.getRawY(); switch(event.getAction()){ case MotionEvent.ACTION_DOWN: dx = cx; dy = cy; tx = lpIv.leftMargin; ty = lpIv.topMargin; break; case MotionEvent.ACTION_MOVE: //同样有效 //btn.setTranslationX(tx + (cx - dx)); //btn.setTranslationY(ty + (cy - dy)); lpIv.leftMargin = (int)(tx + (cx - dx)); lpIv.topMargin = (int)(ty + (cy - dy)); iv.setLayoutParams(lpIv); break; } return true; } }); rlRoot.addView(iv, lpIv); //SurfaceView rl = new RelativeLayoutX(this); sv = new SurfaceView(this); //当未打开摄像头开始预览时, 显示透明(不设置则显示黑色) //sv.setZOrderOnTop(true); //sv.getHolder().setFormat(PixelFormat.TRANSLUCENT); rl.addView(sv, new RelativeLayout.LayoutParams(UiTools.MATCH_PARENT, UiTools.MATCH_PARENT)); cameraHelper = new CameraHelper(camBase.getParameters(cameraId), sv, camBase); rlRoot.addView(rl); //MUST add view overlay //rl.addView(new View(this)); RelativeLayout.LayoutParams lpBtn = new RelativeLayout.LayoutParams(UiTools.WRAP_CONTENT, UiTools.WRAP_CONTENT); Button btn = new Button(this); btn.setText("Show"); //设置输入监听, 用于拖动按键位置. btn.setOnTouchListener(new View.OnTouchListener() { float cx, cy, dx, dy; int tx, ty; @Override public boolean onTouch(View v, MotionEvent event) { cx = event.getRawX(); cy = event.getRawY(); switch(event.getAction()){ case MotionEvent.ACTION_DOWN: dx = cx; dy = cy; tx = lpBtn.leftMargin; ty = lpBtn.topMargin; break; case MotionEvent.ACTION_MOVE: lpBtn.leftMargin = (int)(tx + (cx - dx)); lpBtn.topMargin = (int)(ty + (cy - dy)); btn.setLayoutParams(lpBtn); break; case MotionEvent.ACTION_UP: //开始预览 cameraHelper.openCamera(false); cameraHelper.startPreview(null); //必须设置为FALSE //sv.setZOrderOnTop(false); rlRoot.requestLayout(); break; } return false; } }); rlRoot.addView(btn, lpBtn); setContentView(rlRoot); } @Override protected void onDestroy() { super.onDestroy(); cameraHelper.stopPreview(); } static class RelativeLayoutX extends RelativeLayout{ public RelativeLayoutX(Context context) { super(context); } Path path = new Path(); @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { super.onSizeChanged(w, h, oldw, oldh); path.reset(); path.addCircle(w/2f, h/2f, Math.min(w, h)/2f, Path.Direction.CW); } @Override protected void dispatchDraw(Canvas canvas) { //裁剪圆型画布,使SurfaceView显示圆形区域图像 canvas.save(); canvas.clipPath(path); super.dispatchDraw(canvas); canvas.restore(); } } //非关键代码, 主要用于返回打开摄像头预览的参数 CameraHelper.CameraBase camBase = new CameraHelper.CameraBaseSimple(){ @Override public CameraHelper.CameraParams getParameters(int camIndex) { return new CameraHelper.CameraParams(cameraId, 640, 480, 30, 0, 0); } @Override public boolean sameParams(CameraHelper.CameraParams cp) { return true; } @Override public void onPreviewStarted(int camIndex) {} @Override public void onCameraError(int error) {} }; }PS虽然提出了需求, 也实现了想要的效果, 却也留下了一个问题, 问题虽然解决, 但却找不到具体的原因!1.浮动窗的情况未测试过2.Dialog或其它弹出窗口未测试过3.setZOrderOnTop(true)的情况未有好的解决办法参考解决SurfaceView渲染的各种疑难杂症android 圆形相机预览拍照_Android相机(摄像头)圆形预览窗口,圆形SurfaceView
平台 Android 11 + RK3566概述在应用层通过JNI操作主板上的GPIO.一些小提示:注意文件操作权限, 若在adb shell下可以成功操作, APP下操作失败, 注意排查下权限问题:相关的几个文件 export和unexport, 默认情况下, 权限并没有给这么宽, 参考下面的修改, 以保证APP能有正确认的操作权限.rk3566:/sys/class/gpio # ll /sys/class/gpio -rw-rw-rw- 1 root root 4096 2022-07-20 10:36 export -rw----rw- 1 root root 4096 2022-07-20 10:19 unexport第二部分, 在成功export后, 对应的节点下的权限, 下面对应的是gpio93代码中需要用到的两个文件节点:ll /sys/class/gpio/gpio93/ total 0 -rw-rw-rw- 1 root root 4096 2022-07-20 10:36 direction -rw-rw-rw- 1 root root 4096 2022-07-20 10:36 value代码目录结构:src └── main ├── AndroidManifest.xml ├── cpp │ ├── CMakeLists.txt │ └── jniapi.cpp ├── java │ └── com │ └── android │ └── apitester │ ├── Gpio.java │ └── utils │ └── JniApi.java ├── res │ ├── layout │ │ ├── activity_gpio.xmlGPIO.javapackage com.android.apitester; import android.app.Activity; import android.os.Bundle; import android.view.View; import android.widget.EditText; import android.widget.Switch; import android.widget.Toast; import com.android.apitester.utils.JniApi; public class Gpio extends Activity implements View.OnClickListener { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_gpio); findViewById(R.id.btGpio).setOnClickListener(this); } @Override public void onClick(View view) { JniApi api = new JniApi(); int gpio = Integer.valueOf(((EditText)findViewById(R.id.etGpio)).getText().toString()); int val = ((Switch)findViewById(R.id.swValue)).isChecked() ? 1 : 0; int res = api.setGpio(gpio, val); String result = "SUCCESS"; if(res == -1){ result = "OPEN EXPORT failed"; }else if(res == -2){ result = "open DIRECTION failed"; }else if(res == -3){ result = "open VALUE failed"; }else if(res == -4){ result = "write VALUE failed"; }else if(res == -5){ result = "open UNEXPORT failed"; } Toast.makeText(this, result, Toast.LENGTH_LONG).show(); } }activity_gpio.xml<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent"> <EditText android:id="@+id/etGpio" android:layout_width="match_parent" android:layout_height="wrap_content" android:inputType="number" android:gravity="center_horizontal" android:singleLine="true" android:maxLines="1"/> <Switch android:id="@+id/swValue" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="GPIO High/Low:"/> <Button android:id="@+id/btGpio" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="OK"/> </LinearLayout>JniApi.javapackage com.android.apitester.utils; public class JniApi { static { System.loadLibrary("apitester"); } public native int setGpio(int gpio, int value); }jniapi.cpp#include <stdio.h> #include <errno.h> #include <fcntl.h> #include <unistd.h> #include <stdint.h> #include <assert.h> //#include <cutils/log.h> #include <string.h> #include <jni.h> #include <android/log.h> #define LOG_TAG "ApiTester" #define LOGI(...) ((void)__android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)) #define LOGW(...) ((void)__android_log_print(ANDROID_LOG_WARN, LOG_TAG, __VA_ARGS__)) #define LOGE(...) ((void)__android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)) #define LOGD(...) ((void)__android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)) // // Created by anson on 2022/7/20. //extern "C" JNIEXPORT jint JNICALL Java_com_android_apitester_utils_JniApi_setGpio(JNIEnv *env, jobject thiz, jint gpio, jint value) { char direction_file[64]; char value_file[64]; const char* export_file = "/sys/class/gpio/export"; const char* unexport_file = "/sys/class/gpio/unexport"; LOGD("setGpio gpio:%d to value:%d", gpio, value); //export gpio. FILE *export_fp=fopen(export_file,"w"); if(!export_fp){ LOGE("open file %s failed", export_file); return -1; } fprintf(export_fp,"%d", gpio); fclose(export_fp); //set direction output sprintf(direction_file,"/sys/class/gpio/gpio%d/direction", gpio); FILE *direction_fd=fopen(direction_file,"w"); if(!direction_fd){ LOGE("open file %s failed", direction_file); return -2; } fprintf(direction_fd,"out"); fclose(direction_fd); //write value sprintf(value_file,"/sys/class/gpio/gpio%d/value", gpio); int value_fd = open(value_file, O_RDWR); if(value_fd <= 0){ LOGE("open file %s failed", value_file); return -3; } ssize_t size = write(value_fd, value == 0 ? "0" : "1", 1); if(size <= 0){ LOGE("write gpio %s failed", value_file); close(value_fd); return -4; } //unexport gpio FILE *unexport_fd = fopen(unexport_file,"w"); if(!unexport_fd){ LOGE("open file %s failed", unexport_file); return -5; } fprintf(unexport_fd, "%d", gpio); fclose(unexport_fd); return 1; }CMakeLists.txt# For more information about using CMake with Android Studio, read the # documentation: https://d.android.com/studio/projects/add-native-code.html # Sets the minimum version of CMake required to build the native library. cmake_minimum_required(VERSION 3.10.2) # Declares and names the project. project("apitester") # file(GLOB native_srcs "src/main/cpp/*.cpp" "src/main/cpp/dalvik/*.cpp" "src/main/cpp/art/*.cpp" "src/main/cpp/art/*.S") # Creates and names a library, sets it as either STATIC # or SHARED, and provides the relative paths to its source code. # You can define multiple libraries, and CMake builds them for you. # Gradle automatically packages shared libraries with your APK. add_library( # Sets the name of the library. apitester # Sets the library as a shared library. SHARED # Provides a relative path to your source file(s). jniapi.cpp ) # Searches for a specified prebuilt library and stores the path as a # variable. Because CMake includes system libraries in the search path by # default, you only need to specify the name of the public NDK library # you want to add. CMake verifies that the library exists before # completing its build. find_library( # Sets the name of the path variable. log-lib # Specifies the name of the NDK library that # you want CMake to locate. log ) # Specifies libraries CMake should link to your target library. You # can link multiple libraries, such as libraries you define in this # build script, prebuilt third-party libraries, or system libraries. target_link_libraries( # Specifies the target library. apitester # Links the target library to the log library # included in the NDK. ${log-lib} )扩展关于Studio 中创建JNI创建JNI比较简单: 模块名, 右键 > Add C++ to Module伴随而来的一些问题1. CMake中版本兼容问题, 更改为已安装的版本 3.10.2, 修改build.gradle和 CMakeLists.txt2. 创建后, 在Android视图下, 只有一个CPP文件夹其它的问题现象还有:打开CPP文件:android studio this file does not belong to any project target等.不管如何sync或增加/修改文件, 甚至重启Studio也不能解决, 始终看不到CPP目录下的文件.最后解决:找到项目目录下的setttings.gradle注释当前的模块 -> sync now 去掉模块注释 -> sync now3. 新增加JNI函数: 选中函数 ALT + ENTER之后会有一个文件选择列表, 选中想要添加的位置即可自动生成代码, 相当方便
前言本文为继RK3128 Android 7 BOX SDK 修改为MID界面 与 RK3128 Android 7 BOX SDK 修改为MID界面-近期任务 后续.问题三方应用无法通过接收开机完成广播(BOOT_COMPLETED)完成自启.LOG如下Unable to launch app com.test/10033 for broadcast Intent { act=android.intent.action.BOOT_COMPLETED flg=0x9000010 (has extras) }: process is bad分析解决首先, LOG输出的位置:frameworks/base/services/core/java/com/android/server/am/BroadcastQueue.javaif ((r.curApp=mService.startProcessLocked(targetProcess, info.activityInfo.applicationInfo, true, r.intent.getFlags() | Intent.FLAG_FROM_BACKGROUND, "broadcast", r.curComponent, (r.intent.getFlags()&Intent.FLAG_RECEIVER_BOOT_UPGRADE) != 0, false, false)) == null) { // Ah, this recipient is unavailable. Finish it if necessary, // and mark the broadcast record as ready for the next. Slog.w(TAG, "Unable to launch app " + info.activityInfo.applicationInfo.packageName + "/" + info.activityInfo.applicationInfo.uid + " for broadcast " + r.intent + ": process is bad");frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.javafinal ProcessRecord startProcessLocked(String processName, ApplicationInfo info, boolean knownToBeDead, int intentFlags, String hostingType, ComponentName hostingName, boolean allowWhileBooting, boolean isolated, boolean keepIfLarge) { return startProcessLocked(processName, info, knownToBeDead, intentFlags, hostingType, hostingName, allowWhileBooting, isolated, 0 /* isolatedUid */, keepIfLarge, null /* ABI override */, null /* entryPoint */, null /* entryPointArgs */, null /* crashHandler */); } final ProcessRecord startProcessLocked(String processName, ApplicationInfo info, boolean knownToBeDead, int intentFlags, String hostingType, ComponentName hostingName, boolean allowWhileBooting, boolean isolated, int isolatedUid, boolean keepIfLarge, String abiOverride, String entryPoint, String[] entryPointArgs, Runnable crashHandler) { //...省略中间代码... if((("true".equals(SystemProperties.get("ro.config.low_ram", "false"))) ||("true".equals(SystemProperties.get("ro.mem_optimise.enable", "false")))) && (!"true".equals(SystemProperties.get("cts_gts.status", "false")))){ final ActivityRecord next = getFocusedStack().topRunningActivityLocked(); if(next!= null && (!next.packageName.equals(processName)&& !processName.contains("antutu")) && next.packageName.contains("antutu")){ if(DEBUG_LOWMEM)Slog.v("xzj", "process dont start because for antutu: " + next.packageName + "/" + info.processName); return null; } if((mProcessMap.get(processName) != null) && (("broadcast".equals(hostingType))||("content provider".equals(hostingType)))){ if(DEBUG_LOWMEM)Slog.v("xzj", "process dont start because for filter: " + info.uid + "/" + info.processName); return null; } if((mServiceMap.get(processName) != null)&&("service".equals(hostingType))&&((info.flags & ApplicationInfo.FLAG_IS_GAME) !=0)) //for service start by system { if(DEBUG_LOWMEM)Slog.v("xzj", "service dont start auto because for filter: " + info.uid + "/" + info.processName); return null; } if(((info.flags & ApplicationInfo.FLAG_SYSTEM) ==0)&&("broadcast".equals(hostingType))) { //从这里返回 if(DEBUG_LOWMEM)Slog.v("xzj", "third part process dont start for broadcast: " + info.uid + "/" + info.processName); return null; } if(mGameMap.get(processName) != null) { killAllBackgroundProcesses(); if(DEBUG_LOWMEM)Slog.v("xzj", "----clean memory for start " + info.processName); } }基本可以定位问题点, 进一步验证://获取属性值: rk3128_box:/ $ getprop ro.mem_optimise.enable true判断非系统应用则返回处理.if(((info.flags & ApplicationInfo.FLAG_SYSTEM) ==0)&&("broadcast".equals(hostingType)))ro.mem_optimise.enable从属性名可以推断出这是为了优化低内存平台的用户体验, 减少自启应用以降低系统的内存占用率.解决的方案:1.ro.mem_optimise.enable 设置为false2.以上代码中增加白名单, 允许指定第三方应用自启眠休不黑屏设置休眠15秒后, 屏幕只是变暗而不关闭:diff --git a/device/rockchip/common/tv/overlay/frameworks/base/packages/SettingsProvider/res/values/defaults.xml b/device/rockchip/common/tv/overlay/frameworks/base/packages/SettingsProvider/res/values/defaults.xml index 40021f719c..92bdfb40b9 100644 --- a/device/rockchip/common/tv/overlay/frameworks/base/packages/SettingsProvider/res/values/defaults.xml +++ b/device/rockchip/common/tv/overlay/frameworks/base/packages/SettingsProvider/res/values/defaults.xml @@ -26,7 +26,7 @@ <bool name="def_device_provisioned">true</bool> <!-- Keep screen on at all times by default --> - <bool name="def_stay_on_while_plugged_in">true</bool> + <bool name="def_stay_on_while_plugged_in">false</bool> <!-- Do not give up on DHCP --> <integer name="def_max_dhcp_retries">0</integer>相当代码可以参考看看进入休眠前的几个函数:PowerManagerService |-- handleUserActivityTimeout |-- updatePowerStateLocked |-- updateWakefulnessLocked //不进黑屏是到这里后没有进入下一个函数 |-- goToSleepNoUpdateLocked //进入休眠frameworks/base/services/core/java/com/android/server/power/PowerManagerService.javamStayOnWhilePluggedInSetting = Settings.Global.getInt(resolver, Settings.Global.STAY_ON_WHILE_PLUGGED_IN, BatteryManager.BATTERY_PLUGGED_AC); /** * Updates the value of mStayOn. * Sets DIRTY_STAY_ON if a change occurred. */ private void updateStayOnLocked(int dirty) { if ((dirty & (DIRTY_BATTERY_STATE | DIRTY_SETTINGS)) != 0) { final boolean wasStayOn = mStayOn; if (mStayOnWhilePluggedInSetting != 0 && !isMaximumScreenOffTimeoutFromDeviceAdminEnforcedLocked()) { mStayOn = mBatteryManagerInternal.isPowered(mStayOnWhilePluggedInSetting); } else { mStayOn = false; } if (mStayOn != wasStayOn) { mDirty |= DIRTY_STAY_ON; } } } /** * Returns true if the device should go to sleep now. * Also used when exiting a dream to determine whether we should go back * to being fully awake or else go to sleep for good. */ private boolean isItBedTimeYetLocked() { return mBootCompleted && !isBeingKeptAwakeLocked(); } /** * Returns true if the device is being kept awake by a wake lock, user activity * or the stay on while powered setting. We also keep the phone awake when * the proximity sensor returns a positive result so that the device does not * lock while in a phone call. This function only controls whether the device * will go to sleep or dream which is independent of whether it will be allowed * to suspend. */ private boolean isBeingKeptAwakeLocked() { return mStayOn || mProximityPositive || (mWakeLockSummary & WAKE_LOCK_STAY_AWAKE) != 0 || (mUserActivitySummary & (USER_ACTIVITY_SCREEN_BRIGHT | USER_ACTIVITY_SCREEN_DIM)) != 0 || mScreenBrightnessBoostInProgress; } /** * Updates the wakefulness of the device. * * This is the function that decides whether the device should start dreaming * based on the current wake locks and user activity state. It may modify mDirty * if the wakefulness changes. * * Returns true if the wakefulness changed and we need to restart power state calculation. */ private boolean updateWakefulnessLocked(int dirty) { boolean changed = false; if ((dirty & (DIRTY_WAKE_LOCKS | DIRTY_USER_ACTIVITY | DIRTY_BOOT_COMPLETED | DIRTY_WAKEFULNESS | DIRTY_STAY_ON | DIRTY_PROXIMITY_POSITIVE | DIRTY_DOCK_STATE)) != 0) { if (mWakefulness == WAKEFULNESS_AWAKE && isItBedTimeYetLocked()) { if (DEBUG_SPEW) { Slog.d(TAG, "updateWakefulnessLocked: Bed time..."); } final long time = SystemClock.uptimeMillis(); if (shouldNapAtBedTimeLocked()) { changed = napNoUpdateLocked(time, Process.SYSTEM_UID); } else { changed = goToSleepNoUpdateLocked(time, PowerManager.GO_TO_SLEEP_REASON_TIMEOUT, 0, Process.SYSTEM_UID); } } } return changed; }
平台CPU: Intel® Core™ i7-8700 CPU @ 3.20GHzDDR: 24GB硬盘: SSD 1TB系统: Ubuntu 20.04 x64概述疫情期间居家办公, 为方便调试, 从清华镜像下载了AOSP的代码准备编译后尝试使用模拟器调试, 编译完成后, 发现模拟器启动不了, 要么卡死, 要么崩溃, 历经波折, 最终更新后得以解决, 特此记录.环境搭建参考, 建议以官方说明或厂商开发文档中的环境搭建说明为主#JDK sudo add-apt-repository ppa:openjdk-r/ppa sudo apt-get update #sudo apt-get install openjdk-7-jdk sudo apt-get install openjdk-8-jdk sudo apt-get install vim sudo apt-get install minicom #追加源 sudo gedit /etc/apt/sources.list + deb http://us.archive.ubuntu.com/ubuntu trusty main universe sudo apt-get update #安装依赖 sudo apt-get install git gnupg flex bison gperf build-essential zip curl libc6-dev libncurses5-dev:i386 x11proto-core-dev libx11-dev:i386 libreadline6-dev:i386 libgl1-mesa-glx:i386 libgl1-mesa-dev g++-multilib tofrodos python-markdown libxml2-utils xsltproc zlib1g-dev:i386 sudo apt-get install lzop libncurses5 sudo ln -s /usr/lib/i386-linux-gnu/mesa/libGL.so.1 /usr/lib/i386-linux-gnu/libGL.so sudo apt-get install mingw32 sudo apt-get install automake make perl gcc g++ sudo apt-get install libncurses5 # make kernel # scripts/extract-cert.c:21:10: fatal error: openssl/bio.h: No such file or directory # 21 | #include <openssl/bio.h> # | ^~~~~~~~~~~~~~~ sudo apt-get install libssl-dev #Android编译环境补充 sudo ln -sf /usr/bin/python2.7 /usr/bin/python #ifconfig sudo apt install net-tools # 编译RK3399_LINUX 时出现: [awk: line 2: function strtonum never defined] https://blog.csdn.net/liangtianmeng/article/details/86020254 sudo apt-get install gawk ## Android 11 u-boot sudo apt-get install device-tree-compiler ## X2000 kernel sudo apt install u-boot-tools ## make menuconfig 失败 sudo apt-get install libncurses5-dev获取源码并编译下载:Android 镜像使用帮助编译:source ./build/envsetup.sh #官网中使用的是: lunch aosp_arm-eng #由于需要使用模拟器等相关开发环境, 本文编译直接使用, # 见 https://source.android.com/setup/create/avd lunch sdk_phone_x86_64 make -j12编译时长:#### build completed successfully (02:11:17 (hh:mm:ss)) ####启动模拟器:## 在编译完成后可以直接运行 ## 若关闭了终端, 或重新加载了环境, 则有可能导致执行错误, ## 建议执行前确认是否已经执行 ## source ./build/envsetup.sh ## lunch xxxx $ emulator官网说明模拟器启动成功一些问题编译问题Linux ps 命令导致AOSP编译失败内存至少16GB, 刚开始只用8G, 单线程编译也会卡死.模拟器无法正常启动最早下载源码的时间是2022年3月1日而直至2022年4月17日才成功把模拟器成功跑起来.而解决的方法: 同步到最新 同步到最新 同步到最新旧的代码第一次编译完成后, 无法启动$source build/envsetup.sh $lunch sdk_x86_64 $make $emulator INFO | Android emulator version 31.3.5.0 (build_id 8311694) (CL:N/A) INFO | Duplicate loglines will be removed, if you wish to see each indiviudal line launch with the -log-nofilter flag. WARNING | encryption is off WARNING | cannot add library /media/anson/codes/aosp/prebuilts/android-emulator/linux-x86_64/qemu/linux-x86_64/lib64/vulkan/libvulkan.so: failed INFO | added library /media/anson/codes/aosp/prebuilts/android-emulator/linux-x86_64/lib64/vulkan/libvulkan.so MESA-INTEL: warning: Performance support disabled, consider sysctl dev.i915.perf_stream_paranoid=0 INFO | configAndStartRenderer: setting vsync to 60 hz WARNING | *** No gRPC protection active, consider launching with the -grpc-use-jwt flag.*** INFO | Started GRPC server at 127.0.0.1:8554, security: Local:none INFO | Advertising in: /run/user/1000/avd/running/pid_6593.ini pulseaudio: set_sink_input_volume() failed pulseaudio: Reason: Invalid argument pulseaudio: set_sink_input_mute() failed pulseaudio: Reason: Invalid argument ERROR | Unable to connect to adb daemon on port: 5037$emulator INFO | Android emulator version 31.3.5.0 (build_id 8311694) (CL:N/A) INFO | Duplicate loglines will be removed, if you wish to see each indiviudal line launch with the -log-nofilter flag. ERROR | No initial system image for this configuration!刚开始怀疑是系统环境问题, 于是又配置了硬件加速还有虚拟技术等功能检测12而后, 根据3提示, 增加命令参数以显示更多的启动信息(增加 -verbose -show-kernel -shell):$ emulator -verbose -show-kernel -shell INFO | Android emulator version 31.3.5.0 (build_id 8311694) (CL:N/A) INFO | Found ANDROID_PRODUCT_OUT: /media/anson/codes/aosp/out/target/product/emulator_x86 INFO | Found build target architecture: x86 INFO | argv[0]: 'emulator'; program directory: '/media/anson/codes/aosp/prebuilts/android-emulator/linux-x86_64' INFO | emuDirName: '/media/anson/codes/aosp/prebuilts/android-emulator/emulator' INFO | Probing for /media/anson/codes/aosp/out/target/product/emulator_x86/kernel-ranchu-64: file missing INFO | try dir /media/anson/codes/aosp/prebuilts/android-emulator/linux-x86_64 INFO | Trying emulator path '/media/anson/codes/aosp/prebuilts/android-emulator/linux-x86_64/qemu/linux-x86_64/qemu-system-i386' INFO | Found target-specific 64-bit emulator binary: /media/anson/codes/aosp/prebuilts/android-emulator/linux-x86_64/qemu/linux-x86_64/qemu-system-i386 INFO | Adding library search path: '/media/anson/codes/aosp/prebuilts/android-emulator/linux-x86_64/lib64' INFO | Adding library search path: '/media/anson/codes/aosp/prebuilts/android-emulator/linux-x86_64/lib64/gles_swiftshader' INFO | Adding library search path: '/media/anson/codes/aosp/prebuilts/android-emulator/linux-x86_64/lib64/libstdc++' VERBOSE | Adding library search path for Qt: '/media/anson/codes/aosp/prebuilts/android-emulator/linux-x86_64/lib64/qt/lib' VERBOSE | Silencing all qWarning(); use qCWarning(...) instead: QT_LOGGING_RULES=default.warning=false VERBOSE | Setting Qt plugin search path: QT_QPA_PLATFORM_PLUGIN_PATH=/media/anson/codes/aosp/prebuilts/android-emulator/linux-x86_64/lib64/qt/plugins VERBOSE | Setting Qt to use software OpenGL: QT_OPENGL=software VERBOSE | Setting QML to use software QtQuick2D: QMLSCENE_DEVICE=softwarecontext VERBOSE | Overriding pre-existing bad Qt high dpi settings... VERBOSE | Setting LD_PRELOAD to /media/anson/codes/aosp/prebuilts/android-emulator/linux-x86_64/lib64/qt/lib/libfreetype.so.6 VERBOSE | emulator: Running :/media/anson/codes/aosp/prebuilts/android-emulator/linux-x86_64/qemu/linux-x86_64/qemu-system-i386 VERBOSE | qemu backend: argv[00] = "/media/anson/codes/aosp/prebuilts/android-emulator/linux-x86_64/qemu/linux-x86_64/qemu-system-i386" VERBOSE | qemu backend: argv[01] = "-verbose" VERBOSE | qemu backend: argv[02] = "-show-kernel" VERBOSE | qemu backend: argv[03] = "-shell" VERBOSE | Concatenated backend parameters: /media/anson/codes/aosp/prebuilts/android-emulator/linux-x86_64/qemu/linux-x86_64/qemu-system-i386 -verbose -show-kernel -shell INFO | Duplicate loglines will be removed, if you wish to see each indiviudal line launch with the -log-nofilter flag. VERBOSE | found Android build root: /media/anson/codes/aosp VERBOSE | found Android build out: /media/anson/codes/aosp/out/target/product/emulator_x86 VERBOSE | Cannot find boot properties file: /media/anson/codes/aosp/out/target/product/emulator_x86/boot.prop VERBOSE | Found target API sdkVersion: 32 VERBOSE | Invalid int property: 'ro.build.version.incremental:eng.anson.20220320.212450' VERBOSE | autoconfig: -skin HVGA VERBOSE | autoconfig: -skindir /media/anson/codes/aosp/development/tools/emulator/skins/ VERBOSE | autoconfig: -kernel /media/anson/codes/aosp/prebuilts/qemu-kernel/x86/ranchu/kernel-qemu VERBOSE | Target arch = 'x86' VERBOSE | Auto-config: -qemu -cpu qemu32 VERBOSE | Auto-detect: Kernel image requires new device naming scheme. VERBOSE | Auto-detect: Kernel does not support YAFFS2 partitions. VERBOSE | autoconfig: -ramdisk /media/anson/codes/aosp/out/target/product/emulator_x86/ramdisk-qemu.img VERBOSE | autoconfig: -sysdir /media/anson/codes/aosp/out/target/product/emulator_x86 VERBOSE | Using direct system image: /media/anson/codes/aosp/out/target/product/emulator_x86/system-qemu.img VERBOSE | system partition size adjusted to match image file (4107 MB > 800 MB) VERBOSE | Using direct vendor image: /media/anson/codes/aosp/out/target/product/emulator_x86/vendor-qemu.img VERBOSE | autoconfig: -data /media/anson/codes/aosp/out/target/product/emulator_x86/userdata-qemu.img VERBOSE | autoconfig: -initdata /media/anson/codes/aosp/out/target/product/emulator_x86/userdata.img VERBOSE | autoconfig: -cache /media/anson/codes/aosp/out/target/product/emulator_x86/cache.img VERBOSE | Increasing RAM size to 2048MB VERBOSE | VM heap size 48MB is below hardware specified minimum of 512MB,setting it to that value VERBOSE | System image is read only VERBOSE | Found 1 DNS servers: VERBOSE | 127.0.0.53 VERBOSE | trying to load skin file '/media/anson/codes/aosp/development/tools/emulator/skins//HVGA/layout' WARNING | encryption is off VERBOSE | CPU Acceleration: working VERBOSE | CPU Acceleration status: KVM (version 12) is installed and usable. VERBOSE | handleCpuAcceleration: feature check for hvf VERBOSE | GPU emulation enabled using 'host' mode VERBOSE | Initializing hardware OpenGLES emulation support VERBOSE | create display 0 VERBOSE | setDisplayPose 0 x 0 y 0 w 320 h 480 dpi 0 WARNING | cannot add library /media/anson/codes/aosp/prebuilts/android-emulator/linux-x86_64/qemu/linux-x86_64/lib64/vulkan/libvulkan.so: failed INFO | added library /media/anson/codes/aosp/prebuilts/android-emulator/linux-x86_64/lib64/vulkan/libvulkan.so MESA-INTEL: warning: Performance support disabled, consider sysctl dev.i915.perf_stream_paranoid=0 INFO | configAndStartRenderer: setting vsync to 60 hz VERBOSE | Found 1 DNS servers: VERBOSE | 127.0.0.53 INFO | Content of hardware configuration file: INFO | hw.cpu.arch = x86 INFO | hw.cpu.model = qemu32 INFO | hw.cpu.ncore = 2 INFO | hw.ramSize = 2048 INFO | hw.screen = multi-touch INFO | hw.mainKeys = true INFO | hw.trackBall = true INFO | hw.keyboard = false INFO | hw.keyboard.lid = false INFO | hw.keyboard.charmap = qwerty2 INFO | hw.dPad = true INFO | hw.rotaryInput = false INFO | hw.gsmModem = true INFO | hw.gps = true INFO | hw.battery = true INFO | hw.accelerometer = true INFO | hw.gyroscope = true INFO | hw.audioInput = true INFO | hw.audioOutput = true INFO | hw.sdCard = true INFO | disk.cachePartition = true INFO | disk.cachePartition.path = /media/anson/codes/aosp/out/target/product/emulator_x86/cache.img INFO | disk.cachePartition.size = 66m INFO | test.quitAfterBootTimeOut = -1 INFO | test.delayAdbTillBootComplete = 0 INFO | test.monitorAdb = 0 INFO | hw.lcd.width = 320 INFO | hw.lcd.height = 480 INFO | hw.lcd.depth = 16 INFO | hw.lcd.density = 160 INFO | hw.lcd.backlight = true INFO | hw.lcd.vsync = 60 INFO | hw.gltransport = pipe INFO | hw.gltransport.asg.writeBufferSize = 1048576 INFO | hw.gltransport.asg.writeStepSize = 4096 INFO | hw.gltransport.asg.dataRingSize = 32768 INFO | hw.gltransport.drawFlushInterval = 800 INFO | hw.displayRegion.0.1.xOffset = -1 INFO | hw.displayRegion.0.1.yOffset = -1 INFO | hw.displayRegion.0.1.width = 0 INFO | hw.displayRegion.0.1.height = 0 INFO | hw.displayRegion.0.2.xOffset = -1 INFO | hw.displayRegion.0.2.yOffset = -1 INFO | hw.displayRegion.0.2.width = 0 INFO | hw.displayRegion.0.2.height = 0 INFO | hw.displayRegion.0.3.xOffset = -1 INFO | hw.displayRegion.0.3.yOffset = -1 INFO | hw.displayRegion.0.3.width = 0 INFO | hw.displayRegion.0.3.height = 0 INFO | hw.display1.width = 0 INFO | hw.display1.height = 0 INFO | hw.display1.density = 0 INFO | hw.display1.xOffset = -1 INFO | hw.display1.yOffset = -1 INFO | hw.display1.flag = 0 INFO | hw.display2.width = 0 INFO | hw.display2.height = 0 INFO | hw.display2.density = 0 INFO | hw.display2.xOffset = -1 INFO | hw.display2.yOffset = -1 INFO | hw.display2.flag = 0 INFO | hw.display3.width = 0 INFO | hw.display3.height = 0 INFO | hw.display3.density = 0 INFO | hw.display3.xOffset = -1 INFO | hw.display3.yOffset = -1 INFO | hw.display3.flag = 0 INFO | hw.multi_display_window = false INFO | hw.gpu.enabled = true INFO | hw.gpu.mode = host INFO | hw.initialOrientation = portrait INFO | hw.camera.back = emulated INFO | hw.camera.front = none INFO | vm.heapSize = 512 INFO | hw.sensors.light = true INFO | hw.sensors.pressure = true INFO | hw.sensors.humidity = true INFO | hw.sensors.proximity = true INFO | hw.sensors.magnetic_field = true INFO | hw.sensors.magnetic_field_uncalibrated = true INFO | hw.sensors.gyroscope_uncalibrated = true INFO | hw.sensors.orientation = true INFO | hw.sensors.temperature = true INFO | hw.sensors.rgbclight = false INFO | hw.sensor.hinge = false INFO | hw.sensor.hinge.count = 0 INFO | hw.sensor.hinge.type = 0 INFO | hw.sensor.hinge.sub_type = 0 INFO | hw.sensor.hinge.fold_to_displayRegion.0.1_at_posture = 1 INFO | hw.sensor.roll = false INFO | hw.sensor.roll.count = 0 INFO | hw.sensor.roll.resize_to_displayRegion.0.1_at_posture = 6 INFO | hw.sensor.roll.resize_to_displayRegion.0.2_at_posture = 6 INFO | hw.sensor.roll.resize_to_displayRegion.0.3_at_posture = 6 INFO | hw.sensors.heart_rate = false INFO | hw.sensors.wrist_tilt = false INFO | hw.useext4 = true INFO | hw.arc = false INFO | hw.arc.autologin = false INFO | kernel.path = /media/anson/codes/aosp/prebuilts/qemu-kernel/x86/ranchu/kernel-qemu INFO | kernel.newDeviceNaming = yes INFO | kernel.supportsYaffs2 = no INFO | disk.ramdisk.path = /media/anson/codes/aosp/out/target/product/emulator_x86/ramdisk-qemu.img INFO | disk.systemPartition.path = /media/anson/codes/aosp/out/target/product/emulator_x86/system-qemu.img INFO | disk.systemPartition.size = 4107m INFO | disk.vendorPartition.path = /media/anson/codes/aosp/out/target/product/emulator_x86/vendor-qemu.img INFO | disk.vendorPartition.size = 800m INFO | disk.dataPartition.path = /media/anson/codes/aosp/out/target/product/emulator_x86/userdata-qemu.img INFO | disk.dataPartition.size = 800m INFO | PlayStore.enabled = false INFO | avd.name = <build> INFO | avd.id = <build> INFO | fastboot.forceColdBoot = false INFO | android.avd.home = /home/anson/.android/avd INFO | . INFO | QEMU options list: INFO | argv[00] = "/media/anson/codes/aosp/prebuilts/android-emulator/linux-x86_64/qemu/linux-x86_64/qemu-system-i386" INFO | argv[01] = "-dns-server" INFO | argv[02] = "127.0.0.53" INFO | argv[03] = "-mem-path" INFO | argv[04] = "/media/anson/codes/aosp/out/target/product/emulator_x86/snapshots/default_boot/ram.img" INFO | argv[05] = "-mem-file-shared" INFO | argv[06] = "-serial" INFO | argv[07] = "stdio" INFO | argv[08] = "-device" INFO | argv[09] = "goldfish_pstore,addr=0xff018000,size=0x10000,file=/media/anson/codes/aosp/out/target/product/emulator_x86/build.avd/data/misc/pstore/pstore.bin" INFO | argv[10] = "-cpu" INFO | argv[11] = "android32" INFO | argv[12] = "-enable-kvm" INFO | argv[13] = "-smp" INFO | argv[14] = "cores=2" INFO | argv[15] = "-m" INFO | argv[16] = "2048" INFO | argv[17] = "-lcd-density" INFO | argv[18] = "160" INFO | argv[19] = "-object" INFO | argv[20] = "iothread,id=disk-iothread" INFO | argv[21] = "-nodefaults" INFO | argv[22] = "-kernel" INFO | argv[23] = "/media/anson/codes/aosp/prebuilts/qemu-kernel/x86/ranchu/kernel-qemu" INFO | argv[24] = "-initrd" INFO | argv[25] = "/media/anson/codes/aosp/out/target/product/emulator_x86/ramdisk-qemu.img" INFO | argv[26] = "-drive" INFO | argv[27] = "if=none,index=0,id=system,if=none,file=/media/anson/codes/aosp/out/target/product/emulator_x86/system-qemu.img,read-only" INFO | argv[28] = "-device" INFO | argv[29] = "virtio-blk-pci,drive=system,iothread=disk-iothread,modern-pio-notify" INFO | argv[30] = "-drive" INFO | argv[31] = "if=none,index=1,id=cache,if=none,file=/media/anson/codes/aosp/out/target/product/emulator_x86/cache.img.qcow2,overlap-check=none,cache=unsafe,l2-cache-size=1048576" INFO | argv[32] = "-device" INFO | argv[33] = "virtio-blk-pci,drive=cache,iothread=disk-iothread,modern-pio-notify" INFO | argv[34] = "-drive" INFO | argv[35] = "if=none,index=2,id=userdata,if=none,file=/media/anson/codes/aosp/out/target/product/emulator_x86/userdata-qemu.img.qcow2,overlap-check=none,cache=unsafe,l2-cache-size=1048576" INFO | argv[36] = "-device" INFO | argv[37] = "virtio-blk-pci,drive=userdata,iothread=disk-iothread,modern-pio-notify" INFO | argv[38] = "-drive" INFO | argv[39] = "if=none,index=3,id=vendor,if=none,file=/media/anson/codes/aosp/out/target/product/emulator_x86/vendor-qemu.img,read-only" INFO | argv[40] = "-device" INFO | argv[41] = "virtio-blk-pci,drive=vendor,iothread=disk-iothread,modern-pio-notify" INFO | argv[42] = "-netdev" INFO | argv[43] = "user,id=mynet" INFO | argv[44] = "-device" INFO | argv[45] = "virtio-net-pci,netdev=mynet" INFO | argv[46] = "-device" INFO | argv[47] = "virtio-rng-pci" INFO | argv[48] = "-show-cursor" INFO | argv[49] = "-L" INFO | argv[50] = "/media/anson/codes/aosp/prebuilts/android-emulator/linux-x86_64/lib/pc-bios" INFO | argv[51] = "-soundhw" INFO | argv[52] = "hda" INFO | argv[53] = "-vga" INFO | argv[54] = "none" INFO | argv[55] = "-append" INFO | argv[56] = "no_timer_check clocksource=pit no-kvmclock console=ttyS0,38400 cma=4M@0-4G loop.max_part=7 ramoops.mem_address=0xff018000 ramoops.mem_size=0x10000 memmap=0x10000$0xff018000 printk.devkmsg=on qemu=1 androidboot.hardware=ranchu androidboot.serialno=EMULATOR31X3X5X0 qemu.gles=1 qemu.settings.system.screen_off_timeout=1800000 qemu.vsync=60 qemu.gltransport=pipe qemu.gltransport.drawFlushInterval=800 qemu.opengles.version=131072 qemu.dalvik.vm.heapsize=512m qemu.camera_protocol_ver=1 qemu.camera_hq_edge_processing=0 androidboot.android_dt_dir=/sys/bus/platform/devices/ANDR0001:00/properties/android/ androidboot.vbmeta.size=6208 androidboot.vbmeta.hash_alg=sha256 androidboot.vbmeta.digest=1bdf25ee647d5053e6881a5652319e178099c4abef0cfb12263f62cadccfd971 androidboot.console=ttyS0 android.qemud=1 qemu.avd_name=<build>" INFO | argv[57] = "-android-hw" INFO | argv[58] = "/media/anson/codes/aosp/out/target/product/emulator_x86/hardware-qemu.ini" INFO | Concatenated QEMU options: /media/anson/codes/aosp/prebuilts/android-emulator/linux-x86_64/qemu/linux-x86_64/qemu-system-i386 -dns-server 127.0.0.53 -mem-path /media/anson/codes/aosp/out/target/product/emulator_x86/snapshots/default_boot/ram.img -mem-file-shared -serial stdio -device goldfish_pstore,addr=0xff018000,size=0x10000,file=/media/anson/codes/aosp/out/target/product/emulator_x86/build.avd/data/misc/pstore/pstore.bin -cpu android32 -enable-kvm -smp cores=2 -m 2048 -lcd-density 160 -object iothread,id=disk-iothread -nodefaults -kernel /media/anson/codes/aosp/prebuilts/qemu-kernel/x86/ranchu/kernel-qemu -initrd /media/anson/codes/aosp/out/target/product/emulator_x86/ramdisk-qemu.img -drive if=none,index=0,id=system,if=none,file=/media/anson/codes/aosp/out/target/product/emulator_x86/system-qemu.img,read-only -device virtio-blk-pci,drive=system,iothread=disk-iothread,modern-pio-notify -drive if=none,index=1,id=cache,if=none,file=/media/anson/codes/aosp/out/target/product/emulator_x86/cache.img.qcow2,overlap-check=none,cache=unsafe,l2-cache-size=1048576 -device virtio-blk-pci,drive=cache,iothread=disk-iothread,modern-pio-notify -drive if=none,index=2,id=userdata,if=none,file=/media/anson/codes/aosp/out/target/product/emulator_x86/userdata-qemu.img.qcow2,overlap-check=none,cache=unsafe,l2-cache-size=1048576 -device virtio-blk-pci,drive=userdata,iothread=disk-iothread,modern-pio-notify -drive if=none,index=3,id=vendor,if=none,file=/media/anson/codes/aosp/out/target/product/emulator_x86/vendor-qemu.img,read-only -device virtio-blk-pci,drive=vendor,iothread=disk-iothread,modern-pio-notify -netdev user,id=mynet -device virtio-net-pci,netdev=mynet -device virtio-rng-pci -show-cursor -L /media/anson/codes/aosp/prebuilts/android-emulator/linux-x86_64/lib/pc-bios -soundhw hda -vga none -append 'no_timer_check clocksource=pit no-kvmclock console=ttyS0,38400 cma=4M@0-4G loop.max_part=7 ramoops.mem_address=0xff018000 ramoops.mem_size=0x10000 memmap=0x10000$0xff018000 printk.devkmsg=on qemu=1 androidboot.hardwa VERBOSE | Android qemu version 31.3.5.0 (build_id 8311694) (CL:N/A) VERBOSE | Starting QEMU main loop VERBOSE | registered 'boot-properties' qemud service VERBOSE | Adding boot property: 'ro.opengles.version' = '131072' VERBOSE | Adding boot property: 'qemu.sf.fake_camera' = 'back' VERBOSE | Adding boot property: 'dalvik.vm.heapsize' = '512m' VERBOSE | Adding boot property: 'qemu.hw.mainkeys' = '1' VERBOSE | Adding boot property: 'qemu.sf.lcd_density' = '160' VERBOSE | control console listening on port 5554, ADB on port 5555 VERBOSE | goldfish_events.have-dpad: true VERBOSE | goldfish_events.have-trackball: true VERBOSE | goldfish_events.have-camera: true VERBOSE | goldfish_events.have-keyboard: false VERBOSE | goldfish_events.have-lidswitch: false VERBOSE | goldfish_events.have-tabletmode: false VERBOSE | goldfish_events.have-touch: false VERBOSE | goldfish_events.have-multitouch: true VERBOSE | Not using any http proxy VERBOSE | Adding boot property: 'qemu.timezone' = 'Asia/Shanghai' VERBOSE | android_hw_fingerprint_init: fingerprint qemud listen service initialized WARNING | *** No gRPC protection active, consider launching with the -grpc-use-jwt flag.*** INFO | Started GRPC server at 127.0.0.1:8554, security: Local:none INFO | Advertising in: /run/user/1000/avd/running/pid_7963.ini VERBOSE | emulator_window_fb_rotate VERBOSE | No acpi ini file provided, using default VERBOSE | Adding boot property: 'ro.opengles.version' = '131072' VERBOSE | Adding boot property: 'qemu.sf.fake_camera' = 'back' VERBOSE | Adding boot property: 'dalvik.vm.heapsize' = '512m' VERBOSE | Adding boot property: 'qemu.hw.mainkeys' = '1' VERBOSE | Adding boot property: 'qemu.sf.lcd_density' = '160' VERBOSE | Adding boot property: 'qemu.timezone' = 'Asia/Shanghai' pulseaudio: set_sink_input_volume() failed pulseaudio: Reason: Invalid argument pulseaudio: set_sink_input_mute() failed pulseaudio: Reason: Invalid argument VERBOSE | no root specified: qemu-system-i386: warning: TSC frequency mismatch between VM (3191998 kHz) and host (3191999 kHz), and TSC scaling unavailable qemu-system-i386: warning: TSC frequency mismatch between VM (3191998 kHz) and host (3191999 kHz), and TSC scaling unavailable VERBOSE | Path:/media/anson/codes/aosp/out/host/linux-x86/bin/adb protocol version: 41 VERBOSE | Path:/media/anson/codes/aosp/out/host/linux-x86/bin/adb protocol version: 41 VERBOSE | Found: 1 adb executables VERBOSE | Adb: /media/anson/codes/aosp/out/host/linux-x86/bin/adb VERBOSE | Path:/media/anson/codes/aosp/out/host/linux-x86/bin/adb protocol version: 41 ERROR | Unable to connect to adb daemon on port: 5037 VERBOSE | No acpi ini file provided, using default [ 0.000000] Initializing cgroup subsys cpu [ 0.000000] Initializing cgroup subsys cpuacct [ 0.000000] Linux version 3.18.94+ (android-build@xpcc10.ams.corp.google.com) (gcc version 4.9 20140827 (prerelease) (GCC) ) #1 SMP PREEMPT Mon Feb 12 19:52:31 UTC 2018 [ 0.000000] e820: BIOS-provided physical RAM map: [ 0.000000] BIOS-e820: [mem 0x0000000000000000-0x000000000009fbff] usable [ 0.000000] BIOS-e820: [mem 0x000000000009fc00-0x000000000009ffff] reserved [ 0.000000] BIOS-e820: [mem 0x00000000000f0000-0x00000000000fffff] reserved [ 0.000000] BIOS-e820: [mem 0x0000000000100000-0x000000007ffd7fff] usable [ 0.000000] BIOS-e820: [mem 0x000000007ffd8000-0x000000007fffffff] reserved [ 0.000000] BIOS-e820: [mem 0x00000000feffc000-0x00000000feffffff] reserved [ 0.000000] BIOS-e820: [mem 0x00000000fffc0000-0x00000000ffffffff] reserved [ 0.000000] Notice: NX (Execute Disable) protection missing in CPU! [ 0.000000] e820: user-defined physical RAM map: [ 0.000000] user: [mem 0x0000000000000000-0x000000000009fbff] usable [ 0.000000] user: [mem 0x000000000009fc00-0x000000000009ffff] reserved [ 0.000000] user: [mem 0x00000000000f0000-0x00000000000fffff] reserved [ 0.000000] user: [mem 0x0000000000100000-0x000000007ffd7fff] usable [ 0.000000] user: [mem 0x000000007ffd8000-0x000000007fffffff] reserved [ 0.000000] user: [mem 0x00000000feffc000-0x00000000feffffff] reserved [ 0.000000] user: [mem 0x00000000ff018000-0x00000000ff027fff] reserved [ 0.000000] user: [mem 0x00000000fffc0000-0x00000000ffffffff] reserved [ 0.000000] SMBIOS 2.8 present. [ 0.000000] e820: last_pfn = 0x7ffd8 max_arch_pfn = 0x100000 [ 0.000000] found SMP MP-table at [mem 0x000f5b40-0x000f5b4f] mapped at [c00f5b40] [ 0.000000] init_memory_mapping: [mem 0x00000000-0x000fffff] [ 0.000000] init_memory_mapping: [mem 0x34800000-0x34bfffff] [ 0.000000] init_memory_mapping: [mem 0x30000000-0x347fffff] [ 0.000000] init_memory_mapping: [mem 0x00100000-0x2fffffff] [ 0.000000] init_memory_mapping: [mem 0x34c00000-0x34ffdfff] [ 0.000000] RAMDISK: [mem 0x7fda0000-0x7ffcffff] [ 0.000000] Allocated new RAMDISK: [mem 0x34dbf000-0x34fee4cb] [ 0.000000] Move RAMDISK from [mem 0x7fda0000-0x7ffcf4cb] to [mem 0x34dbf000-0x34fee4cb] [ 0.000000] ACPI: Early table checksum verification disabled [ 0.000000] ACPI: RSDP 0x00000000000F5940 000014 (v00 BOCHS ) [ 0.000000] ACPI: RSDT 0x000000007FFE1B46 000030 (v01 BOCHS BXPCRSDT 00000001 BXPC 00000001) [ 0.000000] ACPI: FACP 0x000000007FFE1A1A 000074 (v01 BOCHS BXPCFACP 00000001 BXPC 00000001) [ 0.000000] ACPI: DSDT 0x000000007FFE0040 0019DA (v01 BOCHS BXPCDSDT 00000001 BXPC 00000001) [ 0.000000] ACPI: FACS 0x000000007FFE0000 000040 [ 0.000000] ACPI: APIC 0x000000007FFE1A8E 000080 (v01 BOCHS BXPCAPIC 00000001 BXPC 00000001) [ 0.000000] ACPI: HPET 0x000000007FFE1B0E 000038 (v01 BOCHS BXPCHPET 00000001 BXPC 00000001) [ 0.000000] 1199MB HIGHMEM available. [ 0.000000] 847MB LOWMEM available. [ 0.000000] mapped low ram: 0 - 34ffe000 [ 0.000000] low ram: 0 - 34ffe000 [ 0.000000] cma: Reserved 4 MiB at 0x34800000 [ 0.000000] Zone ranges: [ 0.000000] DMA [mem 0x00001000-0x00ffffff] [ 0.000000] Normal [mem 0x01000000-0x34ffdfff] [ 0.000000] HighMem [mem 0x34ffe000-0x7ffd7fff] [ 0.000000] Movable zone start for each node [ 0.000000] Early memory node ranges [ 0.000000] node 0: [mem 0x00001000-0x0009efff] [ 0.000000] node 0: [mem 0x00100000-0x7ffd7fff] [ 0.000000] Initmem setup node 0 [mem 0x00001000-0x7ffd7fff] [ 0.000000] Using APIC driver default [ 0.000000] ACPI: PM-Timer IO Port: 0x608 [ 0.000000] ACPI: LAPIC (acpi_id[0x00] lapic_id[0x00] enabled) [ 0.000000] ACPI: LAPIC (acpi_id[0x01] lapic_id[0x01] enabled) [ 0.000000] ACPI: LAPIC_NMI (acpi_id[0xff] dfl dfl lint[0x1]) [ 0.000000] ACPI: IOAPIC (id[0x00] address[0xfec00000] gsi_base[0]) [ 0.000000] IOAPIC[0]: apic_id 0, version 17, address 0xfec00000, GSI 0-23 [ 0.000000] ACPI: INT_SRC_OVR (bus 0 bus_irq 0 global_irq 2 dfl dfl) [ 0.000000] ACPI: INT_SRC_OVR (bus 0 bus_irq 5 global_irq 5 high level) [ 0.000000] ACPI: INT_SRC_OVR (bus 0 bus_irq 9 global_irq 9 high level) [ 0.000000] ACPI: INT_SRC_OVR (bus 0 bus_irq 10 global_irq 10 high level) [ 0.000000] ACPI: INT_SRC_OVR (bus 0 bus_irq 11 global_irq 11 high level) [ 0.000000] Using ACPI (MADT) for SMP configuration information [ 0.000000] ACPI: HPET id: 0x8086a201 base: 0xfed00000 [ 0.000000] smpboot: Allowing 2 CPUs, 0 hotplug CPUs [ 0.000000] e820: [mem 0x80000000-0xfeffbfff] available for PCI devices [ 0.000000] setup_percpu: NR_CPUS:512 nr_cpumask_bits:512 nr_cpu_ids:2 nr_node_ids:1 [ 0.000000] PERCPU: Embedded 15 pages/cpu @f4d94000 s31936 r0 d29504 u61440 [ 0.000000] Built 1 zonelists in Zone order, mobility grouping on. Total pages: 522454 [ 0.000000] Kernel command line: no_timer_check clocksource=pit no-kvmclock console=ttyS0,38400 cma=4M@0-4G loop.max_part=7 ramoops.mem_address=0xff018000 ramoops.mem_size=0x10000 memmap=0x10000$0xff018000 printk.devkmsg=on qemu=1 androidboot.hardware=ranchu androidboot.serialno=EMULATOR31X3X5X0 qemu.gles=1 qemu.settings.system.screen_off_timeout=1800000 qemu.vsync=60 qemu.gltransport=pipe qemu.gltransport.drawFlushInterval=800 qemu.opengles.version=131072 qemu.dalvik.vm.heapsize=512m qemu.camera_protocol_ver=1 qemu.camera_hq_edge_processing=0 androidboot.android_dt_dir=/sys/bus/platform/devices/ANDR0001:00/properties/android/ androidboot.vbmeta.size=6208 androidboot.vbmeta.hash_alg=sha256 androidboot.vbmeta.digest=1bdf25ee647d5053e6881a5652319e178099c4abef0cfb12263f62cadccfd971 androidboot.console=ttyS0 android.qemud=1 qemu.avd_name=<build> mac80211_hwsim.mac_prefix=5554 [ 0.000000] PID hash table entries: 4096 (order: 2, 16384 bytes) [ 0.000000] Dentry cache hash table entries: 131072 (order: 7, 524288 bytes) [ 0.000000] Inode-cache hash table entries: 65536 (order: 6, 262144 bytes) [ 0.000000] Initializing CPU#0 [ 0.000000] Initializing HighMem for node 0 (00034ffe:0007ffd8) [ 0.000000] Initializing Movable for node 0 (00000000:00000000) [ 0.000000] Memory: 2062032K/2096600K available (5832K kernel code, 533K rwdata, 3252K rodata, 516K init, 540K bss, 30472K reserved, 4096K cma-reserved, 1228648K highmem) [ 0.000000] virtual kernel memory layout: [ 0.000000] fixmap : 0xfd7b6000 - 0xfffff000 (41252 kB) [ 0.000000] pkmap : 0xfd000000 - 0xfd400000 (4096 kB) [ 0.000000] vmalloc : 0xf57fe000 - 0xfcffe000 ( 120 MB) [ 0.000000] lowmem : 0xc0000000 - 0xf4ffe000 ( 847 MB) [ 0.000000] .init : 0xc0b68000 - 0xc0be9000 ( 516 kB) [ 0.000000] .data : 0xc07b2378 - 0xc0b667c0 (3793 kB) [ 0.000000] .text : 0xc0200000 - 0xc07b2378 (5832 kB) [ 0.000000] Checking if this processor honours the WP bit even in supervisor mode...Ok. [ 0.000000] SLUB: HWalign=32, Order=0-3, MinObjects=0, CPUs=2, Nodes=1 [ 0.000000] Preemptible hierarchical RCU implementation. [ 0.000000] RCU restricting CPUs from NR_CPUS=512 to nr_cpu_ids=2. [ 0.000000] RCU: Adjusting geometry for rcu_fanout_leaf=16, nr_cpu_ids=2 [ 0.000000] NR_IRQS:33024 nr_irqs:440 0 [ 0.000000] console [ttyS0] enabled [ 0.000000] tsc: Fast TSC calibration using PIT [ 0.000000] tsc: Detected 3191.706 MHz processor [ 0.010001] Calibrating delay loop (skipped), value calculated using timer frequency.. 6383.41 BogoMIPS (lpj=31917060) [ 0.020003] pid_max: default: 32768 minimum: 301 [ 0.020452] ACPI: Core revision 20140926 [ 0.021333] ACPI: All ACPI Tables successfully acquired [ 0.021928] Security Framework initialized [ 0.022341] SELinux: Initializing. [ 0.022659] Mount-cache hash table entries: 2048 (order: 1, 8192 bytes) [ 0.023310] Mountpoint-cache hash table entries: 2048 (order: 1, 8192 bytes) [ 0.024181] Initializing cgroup subsys freezer [ 0.024657] Initializing cgroup subsys debug [ 0.025108] CPU: Physical Processor ID: 0 [ 0.025553] CPU: Processor Core ID: 0 [ 0.025926] Last level iTLB entries: 4KB 0, 2MB 0, 4MB 0 [ 0.025926] Last level dTLB entries: 4KB 0, 2MB 0, 4MB 0, 1GB 0 [ 0.027267] Freeing SMP alternatives memory: 28K [ 0.027825] Enabling APIC mode: Flat. Using 1 I/O APICs [ 0.029480] ..TIMER: vector=0x30 apic1=0 pin1=2 apic2=-1 pin2=-1 [ 0.030002] smpboot: CPU0: Intel Android 32-bit virtual processor (fam: 06, model: 06, stepping: 03) [ 0.040000] Performance Events: Broken PMU hardware detected, using software events only. [ 0.040000] Failed to access perfctr msr (MSR c1 is 0) [ 0.190156] x86: Booting SMP configuration: [ 0.191579] .... node #0, CPUs: #1 [ 0.020000] Initializing CPU#1 [ 0.352058] x86: Booted up 1 node, 2 CPUs [ 0.352616] smpboot: Total of 2 processors activated (12773.99 BogoMIPS) [ 0.353331] CPU1: update max cpu_capacity 1024 [ 0.353799] NET: Registered protocol family 16 [ 0.353799] ramoops: using module parameters [ 0.353799] console [pstore-1] enabled [ 0.353799] pstore: Registered ramoops as persistent store backend [ 0.353799] ramoops: attached 0x10000@0xff018000, ecc: 0/0 [ 0.360001] CPU0: update max cpu_capacity 1024 [ 0.380003] cpuidle: using governor ladder [ 0.400010] cpuidle: using governor menu [ 0.400631] ACPI: bus type PCI registered [ 0.401063] PCI: PCI BIOS revision 2.10 entry at 0xfd20f, last bus=0 [ 0.401574] PCI: Using configuration type 1 for base access [ 0.470096] ACPI: Added _OSI(Module Device) [ 0.470914] ACPI: Added _OSI(Processor Device) [ 0.471800] ACPI: Added _OSI(3.0 _SCP Extensions) [ 0.472894] ACPI: Added _OSI(Processor Aggregator Device) [ 0.476481] ACPI: Interpreter enabled [ 0.477364] ACPI Exception: AE_NOT_FOUND, While evaluating Sleep State [\_S1_] (20140926/hwxface-580) [ 0.479611] ACPI Exception: AE_NOT_FOUND, While evaluating Sleep State [\_S2_] (20140926/hwxface-580) [ 0.481310] ACPI: (supports S0 S3 S5) [ 0.482186] ACPI: Using IOAPIC for interrupt routing [ 0.483450] PCI: Using host bridge windows from ACPI; if necessary, use "pci=nocrs" and report a bug [ 0.492115] ACPI: PCI Root Bridge [PCI0] (domain 0000 [bus 00-ff]) [ 0.493592] acpi PNP0A03:00: _OSC: OS supports [Segments] [ 0.494892] acpi PNP0A03:00: _OSC failed (AE_NOT_FOUND); disabling ASPM [ 0.496473] acpi PNP0A03:00: host bridge window [0x400000000-0x800017fff] (ignored, not CPU addressable) [ 0.498334] acpi PNP0A03:00: fail to add MMCONFIG information, can't access extended PCI configuration space under this bridge. [ 0.500077] PCI host bridge to bus 0000:00 [ 0.500836] pci_bus 0000:00: root bus resource [bus 00-ff] [ 0.501826] pci_bus 0000:00: root bus resource [io 0x0000-0x0cf7] [ 0.502751] pci_bus 0000:00: root bus resource [io 0x0d00-0xffff] [ 0.503682] pci_bus 0000:00: root bus resource [mem 0x000a0000-0x000bffff] [ 0.504718] pci_bus 0000:00: root bus resource [mem 0x80000000-0xfebfffff] [ 0.510218] pci 0000:00:01.1: legacy IDE quirk: reg 0x10: [io 0x01f0-0x01f7] [ 0.511130] pci 0000:00:01.1: legacy IDE quirk: reg 0x14: [io 0x03f6] [ 0.511958] pci 0000:00:01.1: legacy IDE quirk: reg 0x18: [io 0x0170-0x0177] [ 0.512757] pci 0000:00:01.1: legacy IDE quirk: reg 0x1c: [io 0x0376] [ 0.513934] pci 0000:00:01.3: can't claim BAR 7 [io 0x0600-0x063f]: address conflict with ACPI PM1a_EVT_BLK [io 0x0600-0x0603] [ 0.515207] pci 0000:00:01.3: quirk: [io 0x0700-0x070f] claimed by PIIX4 SMB [ 0.525956] pci 0000:00:03.0: reg 0x20: can't handle BAR above 4G (bus address 0x800000000) [ 0.535018] pci 0000:00:04.0: reg 0x20: can't handle BAR above 4G (bus address 0x800004000) [ 0.543008] pci 0000:00:05.0: reg 0x20: can't handle BAR above 4G (bus address 0x800008000) [ 0.552240] pci 0000:00:06.0: reg 0x20: can't handle BAR above 4G (bus address 0x80000c000) [ 0.558239] pci 0000:00:07.0: reg 0x20: can't handle BAR above 4G (bus address 0x800010000) [ 0.563441] pci 0000:00:08.0: reg 0x20: can't handle BAR above 4G (bus address 0x800014000) [ 0.566015] pci 0000:00:0b.0: reg 0x14: can't handle BAR larger than 4GB (size 0x3ffffffff) [ 0.570607] ACPI: PCI Interrupt Link [LNKA] (IRQs 5 *10 11) [ 0.571185] ACPI: PCI Interrupt Link [LNKB] (IRQs 5 *10 11) [ 0.573602] ACPI: PCI Interrupt Link [LNKC] (IRQs 5 10 *11) [ 0.574160] ACPI: PCI Interrupt Link [LNKD] (IRQs 5 10 *11) [ 0.574692] ACPI: PCI Interrupt Link [LNKS] (IRQs *9) [ 0.575517] ACPI: Enabled 2 GPEs in block 00 to 0F [ 0.575968] vgaarb: loaded [ 0.576280] SCSI subsystem initialized [ 0.590044] ACPI: bus type USB registered [ 0.590607] usbcore: registered new interface driver usbfs [ 0.591103] usbcore: registered new interface driver hub [ 0.591629] usbcore: registered new device driver usb [ 0.592047] pps_core: LinuxPPS API ver. 1 registered [ 0.592443] pps_core: Software ver. 5.3.6 - Copyright 2005-2007 Rodolfo Giometti <giometti@linux.it> [ 0.593160] PTP clock support registered [ 0.593505] Advanced Linux Sound Architecture Driver Initialized. [ 0.593505] PCI: Using ACPI for IRQ routing [ 0.610006] cfg80211: Calling CRDA to update world regulatory domain [ 0.610533] NetLabel: Initializing [ 0.610811] NetLabel: domain hash size = 128 [ 0.611152] NetLabel: protocols = UNLABELED CIPSOv4 [ 0.611550] NetLabel: unlabeled traffic allowed by default [ 0.612275] amd_nb: Cannot enumerate AMD northbridges [ 0.612733] Switched to clocksource hpet [ 0.616600] pnp: PnP ACPI init [ 0.617170] pnp: PnP ACPI: found 5 devices [ 0.649457] pci 0000:00:01.3: BAR 7: [io 0x0600-0x063f] has bogus alignment [ 0.650191] pci 0000:00:03.0: BAR 4: assigned [mem 0x80000000-0x80003fff 64bit pref] [ 0.651388] pci 0000:00:04.0: BAR 4: assigned [mem 0x80004000-0x80007fff 64bit pref] [ 0.652491] pci 0000:00:05.0: BAR 4: assigned [mem 0x80008000-0x8000bfff 64bit pref] [ 0.653626] pci 0000:00:06.0: BAR 4: assigned [mem 0x8000c000-0x8000ffff 64bit pref] [ 0.654738] pci 0000:00:07.0: BAR 4: assigned [mem 0x80010000-0x80013fff 64bit pref] [ 0.655837] pci 0000:00:08.0: BAR 4: assigned [mem 0x80014000-0x80017fff 64bit pref] [ 0.656758] pci 0000:00:0b.0: BAR 1: assigned [mem 0x80018000 64bit disabled] [ 0.657595] pci 0000:00:0b.0: BAR 1: error updating (0x80018004 != 0x000004) [ 0.658309] NET: Registered protocol family 2 [ 0.658784] TCP established hash table entries: 8192 (order: 3, 32768 bytes) [ 0.659343] TCP bind hash table entries: 8192 (order: 4, 65536 bytes) [ 0.659852] TCP: Hash tables configured (established 8192 bind 8192) [ 0.660394] TCP: reno registered [ 0.660650] UDP hash table entries: 512 (order: 2, 16384 bytes) [ 0.661865] UDP-Lite hash table entries: 512 (order: 2, 16384 bytes) [ 0.662394] NET: Registered protocol family 1 [ 0.662755] pci 0000:00:00.0: Limiting direct PCI/PCI transfers [ 0.663224] pci 0000:00:01.0: PIIX3: Enabling Passive Release [ 0.663687] pci 0000:00:01.0: Activating ISA DMA hang workarounds [ 0.664266] Trying to unpack rootfs image as initramfs... [ 0.664723] rootfs image is not initramfs (compression method lz4 not configured); looks like an initrd [ 0.666486] Freeing initrd memory: 2240K [ 0.667395] futex hash table entries: 512 (order: 3, 32768 bytes) [ 0.667906] Initialise system trusted keyring [ 0.668256] audit: initializing netlink subsys (disabled) [ 0.668696] audit: type=2000 audit(1649569721.660:1): initialized [ 0.669277] HugeTLB registered 4 MB page size, pre-allocated 0 pages [ 0.670722] VFS: Disk quotas dquot_6.5.2 [ 0.671067] Dquot-cache hash table entries: 1024 (order 0, 4096 bytes) [ 0.671812] Registering sdcardfs 0.1 [ 0.672141] fuse init (API version 7.23) [ 0.673177] Key type asymmetric registered [ 0.673512] Asymmetric key parser 'x509' registered [ 0.673901] Key type pkcs7_test registered [ 0.674228] bounce: pool size: 64 pages [ 0.674554] Block layer SCSI generic (bsg) driver version 0.4 loaded (major 250) [ 0.675132] io scheduler noop registered [ 0.675448] io scheduler deadline registered [ 0.675796] io scheduler cfq registered (default) [ 0.676209] pci_hotplug: PCI Hot Plug PCI Core version: 0.5 [ 0.683638] input: Power Button as /devices/LNXSYSTM:00/LNXPWRBN:00/input/input0 [ 0.684265] ACPI: Power Button [PWRF] [ 0.701140] ACPI: PCI Interrupt Link [LNKC] enabled at IRQ 11 [ 0.718662] ACPI: PCI Interrupt Link [LNKD] enabled at IRQ 10 [ 0.735675] ACPI: PCI Interrupt Link [LNKA] enabled at IRQ 10 [ 0.752945] ACPI: PCI Interrupt Link [LNKB] enabled at IRQ 11 [ 0.786572] Serial: 8250/16550 driver, 4 ports, IRQ sharing disabled [ 0.809665] 00:04: ttyS0 at I/O 0x3f8 (irq = 4, base_baud = 115200) is a 16550A [ 0.810688] Non-volatile memory driver v1.3 [ 0.812378] Linux agpgart interface v0.103 [ 0.812998] [drm] Initialized drm 1.1.0 20060810 [ 0.814674] brd: module loaded [ 0.815559] loop: module loaded [ 0.816828] vda: vda1 vda2 [ 0.817574] vdb: unknown partition table [ 0.818439] vdc: unknown partition table [ 0.819732] vdd: vdd1 [ 0.820024] Loading iSCSI transport class v2.0-870. [ 0.841063] scsi host0: ata_piix [ 0.851692] scsi host1: ata_piix [ 0.852072] ata1: PATA max MWDMA2 cmd 0x1f0 ctl 0x3f6 bmdma 0xc140 irq 14 [ 0.852618] ata2: PATA max MWDMA2 cmd 0x170 ctl 0x376 bmdma 0xc148 irq 15 [ 0.853205] tun: Universal TUN/TAP device driver, 1.6 [ 0.853694] tun: (C) 1999-2004 Max Krasnyansky <maxk@qualcomm.com> [ 0.854507] e100: Intel(R) PRO/100 Network Driver, 3.5.24-k2-NAPI [ 0.854988] e100: Copyright(c) 1999-2006 Intel Corporation [ 0.855434] e1000: Intel(R) PRO/1000 Network Driver - version 7.3.21-k8-NAPI [ 0.855988] e1000: Copyright (c) 1999-2006 Intel Corporation. [ 0.856457] e1000e: Intel(R) PRO/1000 Network Driver - 2.3.2-k [ 0.856911] e1000e: Copyright(c) 1999 - 2014 Intel Corporation. [ 0.857382] sky2: driver version 1.30 [ 0.857706] PPP generic driver version 2.4.2 [ 0.858068] PPP BSD Compression module registered [ 0.858435] PPP Deflate Compression module registered [ 0.858840] PPP MPPE Compression module registered [ 0.859219] NET: Registered protocol family 24 [ 0.859933] mac80211_hwsim: initializing netlink [ 0.860364] usbcore: registered new interface driver asix [ 0.860813] usbcore: registered new interface driver ax88179_178a [ 0.861304] usbcore: registered new interface driver cdc_ether [ 0.861757] usbcore: registered new interface driver net1080 [ 0.862210] usbcore: registered new interface driver cdc_subset [ 0.862679] usbcore: registered new interface driver zaurus [ 0.863138] usbcore: registered new interface driver cdc_ncm [ 0.863677] ehci_hcd: USB 2.0 'Enhanced' Host Controller (EHCI) Driver [ 0.864226] ehci-pci: EHCI PCI platform driver [ 0.864627] ohci_hcd: USB 1.1 'Open' Host Controller (OHCI) Driver [ 0.865132] ohci-pci: OHCI PCI platform driver [ 0.865494] uhci_hcd: USB Universal Host Controller Interface driver [ 0.866029] usbcore: registered new interface driver usblp [ 0.866483] usbcore: registered new interface driver usb-storage [ 0.866993] mousedev: PS/2 mouse device common for all mice [ 0.868012] input: qwerty2 as /devices/platform/GFSH0002:00/input/input1 [ 0.868734] input: goldfish_rotary as /devices/platform/GFSH0008:00/input/input2 [ 0.869349] usbcore: registered new interface driver xpad [ 0.869794] usbcore: registered new interface driver usb_acecad [ 0.870304] usbcore: registered new interface driver aiptek [ 0.870768] usbcore: registered new interface driver gtco [ 0.871214] usbcore: registered new interface driver hanwang [ 0.871683] usbcore: registered new interface driver kbtab [ 0.872197] rtc_cmos 00:00: RTC can wake from S4 [ 0.872727] rtc_cmos 00:00: rtc core: registered rtc_cmos as rtc0 [ 0.873299] rtc_cmos 00:00: alarms up to one day, y3k, 114 bytes nvram, hpet irqs [ 0.873951] goldfish_rtc GFSH0007:00: rtc core: registered GFSH0007:00 as rtc1 [ 0.874878] device-mapper: uevent: version 1.0.3 [ 0.875302] device-mapper: ioctl: 4.28.0-ioctl (2014-09-17) initialised: dm-devel@redhat.com [ 0.886106] hidraw: raw HID events driver (C) Jiri Kosina [ 0.887057] usbcore: registered new interface driver usbhid [ 0.887508] usbhid: USB HID core driver [ 0.897980] ashmem: initialized [ 0.898471] goldfish_sync: Initialized goldfish sync device [ 0.915871] u32 classifier [ 0.916201] Actions configured [ 0.916477] Netfilter messages via NETLINK v0.30. [ 0.916908] nf_conntrack version 0.5.0 (16384 buckets, 65536 max) [ 0.917488] ctnetlink v0.93: registering with nfnetlink. [ 0.918084] xt_time: kernel timezone is -0000 [ 0.919325] sound hdaudioC0D0: autoconfig: line_outs=1 (0x3/0x0/0x0/0x0/0x0) type:line [ 0.919947] sound hdaudioC0D0: speaker_outs=0 (0x0/0x0/0x0/0x0/0x0) [ 0.920489] sound hdaudioC0D0: hp_outs=0 (0x0/0x0/0x0/0x0/0x0) [ 0.920970] sound hdaudioC0D0: mono: mono_out=0x0 [ 0.921349] sound hdaudioC0D0: inputs: [ 0.921666] sound hdaudioC0D0: Line=0x5 [ 0.922772] ip_tables: (C) 2000-2006 Netfilter Core Team [ 0.923224] arp_tables: (C) 2002 David S. Miller [ 0.923623] TCP: cubic registered [ 0.923888] Initializing XFRM netlink socket [ 0.924320] NET: Registered protocol family 10 [ 0.924961] mip6: Mobile IPv6 [ 0.925202] ip6_tables: (C) 2000-2006 Netfilter Core Team [ 0.925650] sit: IPv6 over IPv4 tunneling driver [ 0.926106] NET: Registered protocol family 17 [ 0.926471] NET: Registered protocol family 15 [ 0.927098] Using IPI No-Shortcut mode [ 0.927482] Loading compiled-in X.509 certificates [ 0.927873] registered taskstats version 1 [ 0.928768] console [netcon0] enabled [ 0.929076] netconsole: network logging started [ 0.929437] otg_wakelock_init: No USB transceiver found [ 0.929885] ALSA device list: [ 0.930189] #0: HDA Intel at 0xfebc0000 irq 11 [ 1.010697] md: Waiting for all devices to be available before autodetect [ 1.011938] md: If you don't use raid, use raid=noautodetect [ 1.013163] md: Autodetecting RAID arrays. [ 1.013957] md: Scanned 0 and added 0 devices. [ 1.014868] md: autorun ... [ 1.015483] md: ... autorun DONE. [ 1.016269] RAMDISK: lz4 image found at block 0 [ 1.017253] RAMDISK: lz4 decompressor not configured! [ 1.018334] Invalid ramdisk decompression routine. Select appropriate config option. [ 1.019999] Kernel panic - not syncing: Could not decompress initial ramdisk image. [ 1.020662] CPU: 1 PID: 1 Comm: swapper/0 Not tainted 3.18.94+ #1 [ 1.020662] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS rel-1.11.1-0-g0551a4be2c-prebuilt.qemu-project.org 04/01/2014 [ 1.020662] 00000000 00000046 f34a3f0c c07a9e6c f35d8600 00000000 f34a3f24 c07a9098 [ 1.020662] 00000000 f35d8600 00000000 00000000 f34a3f64 c0b694be c09ec083 c09ec036 [ 1.020662] c09ec0d7 f3424250 f320a100 00000000 00000003 00000004 f34a3f64 c0a248ae [ 1.020662] Call Trace: [ 1.020662] [<c07a9e6c>] dump_stack+0x45/0x59 [ 1.020662] [<c07a9098>] panic+0x7c/0x17b [ 1.020662] [<c0b694be>] rd_load_image+0x283/0x4a9 [ 1.020662] [<c0b697da>] initrd_load+0x3b/0x28a [ 1.020662] [<c0b6905c>] prepare_namespace+0xc2/0x171 [ 1.020662] [<c0b68bd5>] kernel_init_freeable+0x158/0x165 [ 1.020662] [<c07a7b89>] kernel_init+0x8/0xce [ 1.020662] [<c07b0801>] ret_from_kernel_thread+0x21/0x30 [ 1.020662] [<c07a7b81>] ? rest_init+0x70/0x70 [ 1.020662] Kernel Offset: 0x0 from 0xc0200000 (relocation range: 0xc0000000-0xf57fdfff) [ 1.020662] Rebooting in 5 seconds..WARNING | Unknown tab selected.Rebooting in 5 seconds… 跑到这里, 就不停地重启, 循环上面的内核部分的LOG, 模拟器只显示一个框和黑色界面, 不出现任何图像后续尝试过launch不同的类型, 如lunch sdk_phone64_arm64 均无法解决上述问题查阅不同的kernel尝试替换仍然一无所获.aosp/prebuilts/qemu-kernel$ find . -name "kernel-qemu" ./arm64/3.10/kernel-qemu ./arm64/kernel-qemu ./arm64/ranchu/kernel-qemu ./arm/3.10/kernel-qemu ./arm/kernel-qemu ./arm/ranchu/kernel-qemu ./x86_64/3.10/kernel-qemu ./x86_64/kernel-qemu ./x86_64/ranchu/kernel-qemu ./mips/3.10/kernel-qemu ./mips/kernel-qemu ./mips/ranchu/kernel-qemu ./x86/3.10/kernel-qemu ./x86/kernel-qemu ./x86/ranchu/kernel-qemu ./mips64/3.10/kernel-qemu ./mips64/kernel-qemu ./mips64/ranchu/kernel-qemu无奈之下, 尝试更新仓库, 意外地解决了,附: 生成的相关文件$ ll out/target/product/emulator_x86_64/ total 8831116 drwxrwxr-x 26 anson anson 4096 4月 17 06:38 ./ drwxrwxr-x 3 anson anson 4096 4月 16 10:10 ../ -rw-rw-r-- 1 anson anson 660 4月 16 10:12 advancedFeatures.ini -rw-rw-r-- 1 anson anson 22 4月 16 10:12 android-info.txt drwxrwxr-x 32 anson anson 4096 4月 16 12:39 apex/ drwxrwxr-x 2 anson anson 4096 4月 16 13:06 appcompat/ drwxrwxr-x 3 anson anson 4096 4月 16 15:51 build.avd/ -rw-rw-r-- 1 anson anson 90 4月 16 10:11 build_fingerprint.txt -rw-rw-r-- 1 anson anson 61 4月 16 10:11 build_thumbprint.txt drwxrwxr-x 2 anson anson 4096 4月 16 12:23 cache/ -rw-rw-r-- 1 anson anson 16777216 4月 16 12:23 cache.img -rw-r--r-- 1 anson anson 196616 4月 16 15:50 cache.img.qcow2 -rw-rw-r-- 1 anson anson 193024 4月 16 10:10 clean_steps.mk -rw-rw-r-- 1 anson anson 417 4月 16 10:12 config.ini -rw-rw-r-- 1 anson anson 48 4月 16 10:11 .copied_headers_list drwxrwxr-x 4 anson anson 4096 4月 16 10:12 data/ drwxrwxr-x 2 anson anson 4096 4月 16 12:23 debug_ramdisk/ drwxrwxr-x 2 anson anson 12288 4月 16 12:06 dexpreopt_config/ -rw-rw-r-- 1 anson anson 13 4月 16 10:12 dtb.img -rw-rw-r-- 1 anson anson 186 4月 17 06:38 emu-launch-params.txt -rw-rw-r-- 1 anson anson 18874368 4月 16 10:12 encryptionkey.img -rw-r--r-- 1 anson anson 2031616 4月 17 06:01 encryptionkey.img.qcow2 drwxrwxr-x 2 anson anson 4096 4月 16 12:13 fake_packages/ drwxrwxr-x 4 anson anson 4096 4月 16 10:43 gen/ -rw-rw-r-- 1 anson anson 3607 4月 17 06:38 hardware-qemu.ini -rw-rw-r-- 1 anson anson 2290696 4月 17 06:38 initrd -rw-rw-r-- 1 anson anson 3567300 4月 16 10:11 .installable_files.previous -rw-rw-r-- 1 anson anson 416060 4月 16 13:05 installed-files.json -rw-rw-r-- 1 anson anson 52258 4月 16 13:02 installed-files-product.json -rw-rw-r-- 1 anson anson 18853 4月 16 13:02 installed-files-product.txt -rw-rw-r-- 1 anson anson 777 4月 16 12:23 installed-files-ramdisk-debug.json -rw-rw-r-- 1 anson anson 228 4月 16 12:23 installed-files-ramdisk-debug.txt -rw-rw-r-- 1 anson anson 304 4月 16 12:23 installed-files-ramdisk.json -rw-rw-r-- 1 anson anson 81 4月 16 12:23 installed-files-ramdisk.txt -rw-rw-r-- 1 anson anson 2597 4月 16 10:13 installed-files-root.json -rw-rw-r-- 1 anson anson 560 4月 16 10:13 installed-files-root.txt -rw-rw-r-- 1 anson anson 6413 4月 16 13:06 installed-files-system_ext.json -rw-rw-r-- 1 anson anson 2366 4月 16 13:06 installed-files-system_ext.txt -rw-rw-r-- 1 anson anson 133121 4月 16 13:05 installed-files.txt -rw-rw-r-- 1 anson anson 131702 4月 16 13:02 installed-files-vendor.json -rw-rw-r-- 1 anson anson 8800 4月 16 12:23 installed-files-vendor-ramdisk-debug.json -rw-rw-r-- 1 anson anson 2976 4月 16 12:23 installed-files-vendor-ramdisk-debug.txt -rw-rw-r-- 1 anson anson 8327 4月 16 10:44 installed-files-vendor-ramdisk.json -rw-rw-r-- 1 anson anson 2829 4月 16 10:44 installed-files-vendor-ramdisk.txt -rw-rw-r-- 1 anson anson 43642 4月 16 13:02 installed-files-vendor.txt -rw-rw-r-- 1 anson anson 24708960 4月 16 10:12 kernel-ranchu -rw-rw-r-- 1 anson anson 6356 4月 16 10:12 misc_info.txt drwxrwxr-x 3 anson anson 4096 4月 17 01:23 modem_simulator/ -rw-rw-r-- 1 anson anson 49498429 4月 16 10:12 module-info.json -rw-rw-r-- 1 anson anson 53000226 4月 16 10:12 module-info.json.rsp -rw-rw-r-- 1 anson anson 0 4月 17 06:38 multiinstance.lock drwxrwxr-x 13 anson anson 4096 4月 16 13:06 obj/ drwxrwxr-x 6 anson anson 4096 4月 16 11:55 obj_x86/ -rw-rw-r-- 1 anson anson 46 4月 16 10:11 previous_build_config.mk drwxrwxr-x 9 anson anson 4096 4月 16 13:02 product/ -rw-rw-r-- 1 anson anson 313065472 4月 16 13:03 product.img -rw-rw-r-- 1 anson anson 315621376 4月 16 13:03 product-qemu.img -rw-rw-r-- 1 anson anson 18 4月 17 06:38 quickbootChoice.ini drwxrwxr-x 10 anson anson 4096 4月 16 12:23 ramdisk/ -rw-rw-r-- 1 anson anson 1648094 4月 16 12:23 ramdisk.img -rw-rw-r-- 1 anson anson 2288989 4月 16 12:23 ramdisk-qemu.img -rw-rw-r-- 1 anson anson 0 4月 17 06:38 read-snapshot.txt drwxrwxr-x 27 anson anson 4096 4月 16 10:12 root/ drwxr--r-- 3 anson anson 4096 4月 16 15:50 snapshots/ -rw-r--r-- 1 anson anson 4592 4月 16 12:23 super_empty.img -rw-r--r-- 1 anson anson 4303355904 4月 16 13:06 super.img drwxrwxr-x 8 anson anson 4096 4月 16 12:23 symbols/ drwxrwxr-x 14 anson anson 4096 4月 16 13:01 system/ drwxrwxr-x 7 anson anson 4096 4月 16 12:54 system_ext/ -rw-rw-r-- 1 anson anson 138182656 4月 16 13:06 system_ext.img -rw-rw-r-- 1 anson anson 140509184 4月 16 13:06 system_ext-qemu.img -rw-rw-r-- 1 anson anson 1047109632 4月 16 13:05 system.img -rw-rw-r-- 1 anson anson 108 4月 16 13:06 system-qemu-config.txt -rw-rw-r-- 1 anson anson 4306501632 4月 16 13:06 system-qemu.img drwxrwxr-x 2 anson anson 4096 4月 16 10:12 test_harness_ramdisk/ drwxr-xr-x 2 anson anson 4096 4月 17 06:02 tmpAdbCmds/ -rw-rw-r-- 1 anson anson 576716800 4月 16 12:23 userdata.img -rw-r--r-- 1 anson anson 6442450944 4月 16 15:50 userdata-qemu.img -rw-r--r-- 1 anson anson 508821504 4月 17 06:02 userdata-qemu.img.qcow2 -rw-rw-r-- 1 anson anson 8192 4月 16 13:06 vbmeta.img drwxrwxr-x 11 anson anson 4096 4月 16 12:23 vendor/ -rw-rw-r-- 1 anson anson 872448 4月 16 12:23 vendor_boot-debug.img -rw-rw-r-- 1 anson anson 100663296 4月 16 11:51 vendor_boot.img -rw-rw-r-- 1 anson anson 872448 4月 16 12:23 vendor_boot-test-harness.img drwxrwxr-x 2 anson anson 4096 4月 16 12:23 vendor_debug_ramdisk/ -rw-rw-r-- 1 anson anson 161206272 4月 16 13:02 vendor.img -rw-rw-r-- 1 anson anson 163577856 4月 16 13:03 vendor-qemu.img drwxrwxr-x 4 anson anson 4096 4月 16 10:12 vendor_ramdisk/ -rw-rw-r-- 1 anson anson 863456 4月 16 12:23 vendor_ramdisk-debug.img -rw-rw-r-- 1 anson anson 640895 4月 16 10:44 vendor_ramdisk.img -rw-rw-r-- 1 anson anson 863844 4月 16 12:23 vendor_ramdisk-test-harness.img -rw-rw-r-- 1 anson anson 356 4月 16 13:06 VerifiedBootParams.textproto -rw-rw-r-- 1 anson anson 3 4月 16 15:50 version_num.cache附正常启动LOG: android AOSP 模拟器启动成功日志模拟器莫名奇妙崩溃nouveau: kernel rejected pushbuf: Invalid argument nouveau: ch6: krec 0 pushes 0 bufs 2 relocs 0 nouveau: ch6: buf 00000000 00000003 00000004 00000004 00000000 nouveau: ch6: buf 00000001 00000006 00000004 00000000 00000004 nouveau: kernel rejected pushbuf: Invalid argument nouveau: ch6: krec 0 pushes 1 bufs 10 relocs 0 nouveau: ch6: buf 00000000 00000004 00000004 00000004 00000000 nouveau: ch6: buf 00000001 00000004 00000004 00000004 00000000 nouveau: ch6: buf 00000002 00000046 00000002 00000002 00000000 nouveau: ch6: buf 00000003 00000010 00000002 00000002 00000000 nouveau: ch6: buf 00000004 00000008 00000002 00000002 00000000 nouveau: ch6: buf 00000005 00000008 00000002 00000002 00000000 nouveau: ch6: buf 00000006 0000000a 00000002 00000002 00000000 nouveau: ch6: buf 00000007 00000006 00000004 00000000 00000004 nouveau: ch6: buf 00000008 00000016 00000002 00000000 00000002 nouveau: ch6: buf 00000009 00000016 00000002 00000000 00000002 nouveau: ch6: psh 00000001 00000060a0 0000006230 nouveau: 0x200203fd nouveau: 0x05a00000 nouveau: 0x0b900000 nouveau: 0x20090200 Segmentation fault (core dumped)参考4, 问题是由显卡导致的, 可以尝试以下解决办法:打开 Software & Update > Additional Drivers显示卡驱动改为:Using NVIDIA driver metapackage from nvidia-driver-510-server(propietary)重启生效参考Establishing a Build Environment使用清华镜像快速下载Android系统源代码Building AndroidUsing Android Emulator Virtual Devicesaosp 12 编译后无法启动模拟器问题为 Android 模拟器配置硬件加速` ↩︎在 Linux 上配置虚拟机加速 ↩︎Android Emulator(X86) ↩︎Unable to run Genymotion on Ubuntu 14.04 ↩︎
平台Android + 讯飞离线语音SDKSDK包下载路径及方法见讯飞官方SDK文档:离线语音听写 Android SDK 文档 #在开发者控制台, 可以直接下载SDK.SDK包中的文件结构~/Downloads/Android_esriat_exp1143_5a2b58b9$ tree . ├── assets 带UI需要用到的一些图片等资源 │ └── iflytek │ ├── recognize.xml │ ├── voice_bg.9.png │ ├── voice_empty.png │ ├── voice_full.png │ ├── waiting.png │ └── warning.png ├── libs JNI库能JAR包, 只支持v7, v8 64 │ ├── arm64-v8a │ │ └── libmsc.so │ ├── armeabi-v7a │ │ └── libmsc.so │ └── Msc.jar ├── readme.txt ├── release.txt ├── res SDK资源 │ ├── asr │ ├── iat │ │ ├── common.jet │ │ └── sms_16k.jet │ ├── ivw │ ├── layout │ │ └── ifly_layout_mnotice_image.xml │ ├── tts │ └── xtts └── sample 参考DEMO └── mscV5PlusDemo ├── build.gradle ├── libs │ ├── arm64-v8a │ │ └── libmsc.so │ ├── armeabi-v7a │ │ └── libmsc.so │ └── Msc.jar ├── lint.xml ├── msc.cfg └── src └── main ├── AndroidManifest.xml ├── assets │ ├── asr │ ├── call.bnf │ ├── grammar_sample.abnf │ ├── iat │ ├── iattest.wav │ ├── iflytek │ │ ├── recognize.xml │ │ ├── voice_bg.9.png │ │ ├── voice_empty.png │ │ ├── voice_full.png │ │ ├── waiting.png │ │ └── warning.png │ ├── ivw │ ├── layout │ │ └── ifly_layout_mnotice_image.xml │ ├── tts │ ├── userwords │ ├── wake.bnf │ ├── wake_grammar_sample.abnf │ └── xtts ├── java │ └── com │ └── iflytek │ ├── mscv5plusdemo │ │ ├── AsrDemo.java │ │ ├── IatDemo.java │ │ ├── IvwActivity.java │ │ ├── MainActivity.java │ │ ├── OneShotDemo.java │ │ ├── SpeechApp.java │ │ ├── TtsDemo.java │ │ └── WakeDemo.java │ └── speech │ ├── setting │ │ ├── IatSettings.java │ │ └── TtsSettings.java │ └── util │ ├── FucUtil.java │ ├── JsonParser.java │ ├── SettingTextWatcher.java │ └── XmlParser.java └── res ├── drawable │ ├── cancel_button.xml │ ├── list_bg_color.xml │ ├── main_setting_btn_np.xml │ ├── ok_button.xml │ ├── setting.png │ └── setting_p.png ├── drawable-hdpi │ ├── bg.png │ ├── btn_left_f.9.png │ ├── btn_left_n.9.png │ ├── btn_left_p.9.png │ ├── btn_left.xml │ ├── btn_right_f.9.png │ ├── btn_right_n.9.png │ ├── btn_right_p.9.png │ ├── btn_right.xml │ ├── button_login.xml │ ├── cancel.9.png │ ├── cancel_p.9.png │ ├── editbox.9.png │ ├── edittext_name.9.png │ ├── head.png │ ├── icon.png │ ├── login.png │ ├── login_p.png │ ├── mic_0.png │ ├── mic_1.png │ ├── mic_2.png │ ├── mic_3.png │ ├── name_left.png │ ├── name_right.png │ ├── ok.9.png │ ├── ok_d.9.png │ ├── ok_p.9.png │ ├── pane_bg.9.png │ └── superman.9.png ├── drawable-ldpi │ └── icon.png ├── drawable-mdpi │ └── icon.png ├── layout │ ├── iatdemo.xml │ ├── isrdemo.xml │ ├── ivw_activity.xml │ ├── list_items.xml │ ├── main.xml │ ├── oneshot_activity.xml │ ├── title.xml │ ├── ttsdemo.xml │ └── wake_activity.xml ├── values │ ├── colors.xml │ ├── dimen.xml │ ├── strings.xml │ └── styles.xml └── xml ├── iat_setting.xml ├── tts_setting.xml └── understand_setting.xml 42 directories, 101 files使用首先可以尝试使用SDK中的DEMO, 将Sample下的mscV5PlusDemo导入到Android Studio中,~/StudioProjects/TestCodes/mscV5PlusDemo$ ll total 612 drwxrwxr-x 5 anson anson 4096 3月 14 10:43 ./ drwxrwxr-x 20 anson anson 4096 3月 14 10:37 ../ -rw-rw-r-- 1 anson anson 836 3月 14 09:14 build.gradle drwxrwxr-x 4 anson anson 4096 3月 14 10:07 libs/ -rw-rw-r-- 1 anson anson 53 3月 14 09:14 lint.xml -rw-rw-r-- 1 anson anson 5517 3月 14 09:14 msc.cfg drwxrwxr-x 3 anson anson 4096 3月 14 10:07 src/PS: 需要打开 android.useAndroidX=true配置, 有可能还需解决一些JDK版本不支持LAMBA语法的支持,这里略过.运行:一个小插曲: SDK中的DEMO运行离线识别时, DEMO居然报错了??2022-03-14 10:56:34.643 18483-18483/com.iflytek.mscv5plusdemo W/System.err: java.io.FileNotFoundException: iat/common.jet 2022-03-14 10:56:34.643 18483-18483/com.iflytek.mscv5plusdemo W/System.err: at android.content.res.AssetManager.nativeOpenAssetFd(Native Method) 2022-03-14 10:56:34.643 18483-18483/com.iflytek.mscv5plusdemo W/System.err: at android.content.res.AssetManager.openFd(AssetManager.java:966) 2022-03-14 10:56:34.644 18483-18483/com.iflytek.mscv5plusdemo W/System.err: at com.iflytek.cloud.util.ResourceUtil.a(SourceFile:11) 2022-03-14 10:56:34.644 18483-18483/com.iflytek.mscv5plusdemo W/System.err: at com.iflytek.cloud.util.ResourceUtil.generateResourcePath(SourceFile:4) 2022-03-14 10:56:34.644 18483-18483/com.iflytek.mscv5plusdemo W/System.err: at com.iflytek.mscv5plusdemo.IatDemo.getResourcePath(IatDemo.java:358) 2022-03-14 10:56:34.644 18483-18483/com.iflytek.mscv5plusdemo W/System.err: at com.iflytek.mscv5plusdemo.IatDemo.setParam(IatDemo.java:326) 2022-03-14 10:56:34.644 18483-18483/com.iflytek.mscv5plusdemo W/System.err: at com.iflytek.mscv5plusdemo.IatDemo.onClick(IatDemo.java:116) 2022-03-14 10:56:34.644 18483-18483/com.iflytek.mscv5plusdemo W/System.err: at android.view.View.performClick(View.java:7312) 2022-03-14 10:56:34.644 18483-18483/com.iflytek.mscv5plusdemo W/System.err: at android.view.View.performClickInternal(View.java:7286) 2022-03-14 10:56:34.644 18483-18483/com.iflytek.mscv5plusdemo W/System.err: at android.view.View.access$3600(View.java:838) 2022-03-14 10:56:34.644 18483-18483/com.iflytek.mscv5plusdemo W/System.err: at android.view.View$PerformClick.run(View.java:28242) 2022-03-14 10:56:34.644 18483-18483/com.iflytek.mscv5plusdemo W/System.err: at android.os.Handler.handleCallback(Handler.java:900) 2022-03-14 10:56:34.644 18483-18483/com.iflytek.mscv5plusdemo W/System.err: at android.os.Handler.dispatchMessage(Handler.java:103) 2022-03-14 10:56:34.644 18483-18483/com.iflytek.mscv5plusdemo W/System.err: at android.os.Looper.loop(Looper.java:219) 2022-03-14 10:56:34.644 18483-18483/com.iflytek.mscv5plusdemo W/System.err: at android.app.ActivityThread.main(ActivityThread.java:8668) 2022-03-14 10:56:34.644 18483-18483/com.iflytek.mscv5plusdemo W/System.err: at java.lang.reflect.Method.invoke(Native Method) 2022-03-14 10:56:34.644 18483-18483/com.iflytek.mscv5plusdemo W/System.err: at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:513) 2022-03-14 10:56:34.644 18483-18483/com.iflytek.mscv5plusdemo W/System.err: at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1109) 2022-03-14 10:56:34.644 18483-18483/com.iflytek.mscv5plusdemo W/System.err: java.io.FileNotFoundException: iat/sms_16k.jet 2022-03-14 10:56:34.645 18483-18483/com.iflytek.mscv5plusdemo W/System.err: at android.content.res.AssetManager.nativeOpenAssetFd(Native Method) 2022-03-14 10:56:34.645 18483-18483/com.iflytek.mscv5plusdemo W/System.err: at android.content.res.AssetManager.openFd(AssetManager.java:966) 2022-03-14 10:56:34.645 18483-18483/com.iflytek.mscv5plusdemo W/System.err: at com.iflytek.cloud.util.ResourceUtil.a(SourceFile:11) 2022-03-14 10:56:34.645 18483-18483/com.iflytek.mscv5plusdemo W/System.err: at com.iflytek.cloud.util.ResourceUtil.generateResourcePath(SourceFile:4) 2022-03-14 10:56:34.645 18483-18483/com.iflytek.mscv5plusdemo W/System.err: at com.iflytek.mscv5plusdemo.IatDemo.getResourcePath(IatDemo.java:360) 2022-03-14 10:56:34.645 18483-18483/com.iflytek.mscv5plusdemo W/System.err: at com.iflytek.mscv5plusdemo.IatDemo.setParam(IatDemo.java:326) 2022-03-14 10:56:34.645 18483-18483/com.iflytek.mscv5plusdemo W/System.err: at com.iflytek.mscv5plusdemo.IatDemo.onClick(IatDemo.java:116) 2022-03-14 10:56:34.645 18483-18483/com.iflytek.mscv5plusdemo W/System.err: at android.view.View.performClick(View.java:7312) 2022-03-14 10:56:34.645 18483-18483/com.iflytek.mscv5plusdemo W/System.err: at android.view.View.performClickInternal(View.java:7286) 2022-03-14 10:56:34.645 18483-18483/com.iflytek.mscv5plusdemo W/System.err: at android.view.View.access$3600(View.java:838) 2022-03-14 10:56:34.645 18483-18483/com.iflytek.mscv5plusdemo W/System.err: at android.view.View$PerformClick.run(View.java:28242) 2022-03-14 10:56:34.645 18483-18483/com.iflytek.mscv5plusdemo W/System.err: at android.os.Handler.handleCallback(Handler.java:900) 2022-03-14 10:56:34.645 18483-18483/com.iflytek.mscv5plusdemo W/System.err: at android.os.Handler.dispatchMessage(Handler.java:103) 2022-03-14 10:56:34.645 18483-18483/com.iflytek.mscv5plusdemo W/System.err: at android.os.Looper.loop(Looper.java:219) 2022-03-14 10:56:34.645 18483-18483/com.iflytek.mscv5plusdemo W/System.err: at android.app.ActivityThread.main(ActivityThread.java:8668) 2022-03-14 10:56:34.645 18483-18483/com.iflytek.mscv5plusdemo W/System.err: at java.lang.reflect.Method.invoke(Native Method) 2022-03-14 10:56:34.645 18483-18483/com.iflytek.mscv5plusdemo W/System.err: at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:513) 2022-03-14 10:56:34.645 18483-18483/com.iflytek.mscv5plusdemo W/System.err: at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1109)有两个文件找不到: iat/common.jet 和 iat/sms_16k.jet这两个文件在SDK包中的:Android_esriat_exp1143_5a2b58b9/res/iat/ total 32020 drwxr-xr-x 2 anson anson 4096 3月 14 09:14 ./ drwxr-xr-x 8 anson anson 4096 3月 14 09:14 ../ -rw-r--r-- 1 anson anson 9781778 3月 14 09:14 common.jet -rw-r--r-- 1 anson anson 22994400 3月 14 09:14 sms_16k.jet找到并把这两个文件拷贝到项目相应的目录下: src/main/assets/iat/完整文件目录结构如下:├── build.gradle ├── libs │ ├── arm64-v8a │ │ └── libmsc.so │ ├── armeabi-v7a │ │ └── libmsc.so │ └── Msc.jar ├── lint.xml ├── msc.cfg └── src └── main ├── AndroidManifest.xml ├── assets │ ├── asr │ ├── call.bnf │ ├── grammar_sample.abnf │ ├── iat │ │ ├── common.jet │ │ └── sms_16k.jet │ ├── iattest.wav │ ├── iflytek │ │ ├── recognize.xml │ │ ├── voice_bg.9.png │ │ ├── voice_empty.png │ │ ├── voice_full.png │ │ ├── waiting.png │ │ └── warning.png │ ├── ivw │ ├── layout │ │ └── ifly_layout_mnotice_image.xml │ ├── tts │ ├── userwords │ ├── wake.bnf │ ├── wake_grammar_sample.abnf │ └── xtts ├── java │ └── com │ └── iflytek │ ├── mscv5plusdemo │ │ ├── AsrDemo.java │ │ ├── IatDemo.java │ │ ├── IvwActivity.java │ │ ├── MainActivity.java │ │ ├── OneShotDemo.java │ │ ├── SpeechApp.java │ │ ├── TtsDemo.java │ │ └── WakeDemo.java │ └── speech │ ├── setting │ │ ├── IatSettings.java │ │ └── TtsSettings.java │ └── util │ ├── FucUtil.java │ ├── JsonParser.java │ ├── SettingTextWatcher.java │ └── XmlParser.java └── res ├── drawable │ ├── cancel_button.xml │ ├── list_bg_color.xml │ ├── main_setting_btn_np.xml │ ├── ok_button.xml │ ├── setting.png │ └── setting_p.png ├── drawable-hdpi │ ├── bg.png │ ├── btn_left_f.9.png │ ├── btn_left_n.9.png │ ├── btn_left_p.9.png │ ├── btn_left.xml │ ├── btn_right_f.9.png │ ├── btn_right_n.9.png │ ├── btn_right_p.9.png │ ├── btn_right.xml │ ├── button_login.xml │ ├── cancel.9.png │ ├── cancel_p.9.png │ ├── editbox.9.png │ ├── edittext_name.9.png │ ├── head.png │ ├── icon.png │ ├── login.png │ ├── login_p.png │ ├── mic_0.png │ ├── mic_1.png │ ├── mic_2.png │ ├── mic_3.png │ ├── name_left.png │ ├── name_right.png │ ├── ok.9.png │ ├── ok_d.9.png │ ├── ok_p.9.png │ ├── pane_bg.9.png │ └── superman.9.png ├── drawable-ldpi │ └── icon.png ├── drawable-mdpi │ └── icon.png ├── layout │ ├── iatdemo.xml │ ├── isrdemo.xml │ ├── ivw_activity.xml │ ├── list_items.xml │ ├── main.xml │ ├── oneshot_activity.xml │ ├── title.xml │ ├── ttsdemo.xml │ └── wake_activity.xml ├── values │ ├── colors.xml │ ├── dimen.xml │ ├── strings.xml │ └── styles.xml └── xml ├── iat_setting.xml ├── tts_setting.xml └── understand_setting.xml再次运行, 成功!!参考SDK说明
平台RK3566 + Android 11概述为方便第三方应用调用系统功能, 增加系统服务提权并提供应用层调用开放接口, 在Android 9及以下版本已实现基本的实现步骤如下, 服务以MyService命名:1.在frameworks/base/core中增加 IMyService.aidl2.增加IMyService接口实现的应用, 可以存放在frameworks/base/packages/MyService3.修改frameworks/base/services启动MyService, 并增加到SystemService中.4.修改相关SELinux权限.Android 11上的问题相同的补丁, 打到Android 11上, 出现了新的问题.2022-02-10 01:05:48.340 5010-5010/com.ansondroider.apitester W/oider.apiteste: Accessing hidden method Landroid/os/IMyService$Stub;->asInterface(Landroid/os/IBinder;)Landroid/os/IMyService; (blacklist, linking, denied) 2022-02-10 01:05:48.344 5010-5010/com.ansondroider.apitester W/oider.apiteste: Accessing hidden method Landroid/os/IMyService;->reboot(IIIIIII)Z (blacklist, linking, denied) 2022-02-10 01:05:48.346 5010-5010/com.ansondroider.apitester W/oider.apiteste: Accessing hidden method Landroid/os/IMyService;->shutdown(IIIIIII)Z (blacklist, linking, denied)这个问题出现在第三方应用调用接口时, 初始化接口类的过程中, 接口类需要通过调用 IMyService.Stub.asInterface来获取服务实现跨进程调用, LOG中体现为 找不到相关的类, 理论上, 也会影响反射的方式,翻阅了相关资料后, 原因可以查看文末参考内容,解决方法是将增加的接口添加到源码下的hiddenapi-greylist.txt中(不能有空行):frameworks/base/config/hiddenapi-greylist.txtLandroid/os/IMyService$Stub;->asInterface(Landroid/os/IBinder;)Landroid/os/IMyService; Landroid/os/IMyService;->reboot(IIIIIII)Z Landroid/os/IMyService;->shutdown(IIIIIII)Z重新编译打包, 完成!参考1.针对非SDK接口的限制-Google 反射限制2.Android 11 中有关限制非 SDK 接口的更新3.SystemServer 启动新增服务APK
平台Android 8.1 + RK3288Windows 8.1 + Modbus Slave 7.31概述在RK3288的主板上, 支持一路RS485串口, 再将外设通过这路串口连接后, 就可以实现外设与3288的通讯, 由于手上没有外设, 所以采用模拟的方式.连方式如下:准备1.买了一个RS485 U转串, 京东2.Windows 上安装 Modbus Slave下载地址直接装, 压缩中已包含注册码.3.接线:只接2根线开始1.接好线后, 打开Modbus Salve, 并连接.一定要仔细核对串口的参数是否正确, 由于一开始选错了红框中的参数, 导致数据发送不过来, 主要的表现有: 数据不完整, 数据错误. 单独一个一个发正常, 连着发3个以上就出错参考: 串口通信校验方式(even,odd,space,mark)不管GOOGLE还是百度, 都没有人解释为什么Modbus Slave 数据接收不全, 这或许对熟悉的人来说并不算是问题的问题主要参考下Modbus测试工具ModbusPoll与Modbus Slave使用方法红框部分是在调试过程中, 把地址改成了1, 导致读取异常, 特此记录寄存器部分, 很简单, 点击可修改, 数据发生变化也同样会刷新.通俗点可以把它理解为数据库, 没有主动发送数据的功能或接口, 当通讯数据准确, 它会自动把寄存器的数据通过响应发过去.当然, 整个数据处理过程, 均按标准的Modbus协议来2.Android端的实现: 串口通讯实现方式大同小异, 比如Acccord/AndroidSerialPort和利用android-serialport-api进行串口读写操作final UartComm uart = new UartComm(); uart.open("/dev/ttyS0"); int r = uart.setOpt(9600, 8, 0, 1); //剩下读写的实现不作细述.3.ModBus 协议读寄存器SlaveId + Function + address + value + CRC如://读取从 0 开始的 1e(30)个数据 SEND->01 03 00 00 00 1e c5 c2 //返回数据 3C(60)为数据长度对应上面要求的30个, 一个数据2个byte RECV<-01 03 3c 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 7a d7写寄存器SlaveId + Function + address + value + CRC//把地址0a 的值改为 1a SEND->01 06 00 0a 00 1a 28 03 //成功后返回 RECV<-01 06 00 0a 00 1a 28 03写多个寄存器 功能码 0x10(16)SEND->01 10 00 1B 00 03 06 00 DF 00 BE 00 FF 23 47 RECV->01 10 00 1B 00 03 F0 0F更多说明请查阅: Modbus协议中文版.pdf若无法打开, 请自行下载Modbus协议中文版【完整版】.pdf
环境ubuntu 20.04 x64概述测试客户端使用sipdroid服务端刚开始使用的是ASTERISK, 而后改用miniSIPServerASTERISK参考Install Asterisk 18 LTS on Ubuntu 20.04|18.04在ubuntu20.04下, 可以跳过前面的源码编译部分直接安装sudo apt-get install asterisk不使用源码编译的方式是否会导致后面打印输出的错误, 各位自行验证/etc/asterisk/asterisk.confrunuser = asterisk ; The user to run as. rungroup = asterisk ; The group to run as/etc/asterisk/sip.conf[9001] type=friend host=dynamic secret=9001 [9002] type=friend host=dynamic secret=9002/etc/asterisk/extensions.conf[general] static=yes writeprotect=no priorityjumping=no autofallthrough=yes clearglobalvars=no [default] exten => 9001,1,Dial(SIP/9001,10) exten => 9002,1,Dial(SIP/9002,10)anson@anson-MR26:/etc/asterisk$ sudo systemctl status asterisk ● asterisk.service - Asterisk PBX Loaded: loaded (/lib/systemd/system/asterisk.service; enabled; vendor preset: enabled) Active: active (running) since Fri 2021-10-15 19:20:58 CST; 2s ago Docs: man:asterisk(8) Main PID: 80345 (asterisk) Tasks: 77 (limit: 18935) Memory: 38.8M CGroup: /system.slice/asterisk.service ├─80345 /usr/sbin/asterisk -g -f -p -U asterisk └─80346 astcanary /var/run/asterisk/alt.asterisk.canary.tweet.tweet.tweet 80345 10月 15 19:20:58 anson-MR26 asterisk[80345]: [Oct 15 19:20:58] ERROR[80345]: loader.c:2249 load_modules: cel_radius declined to load. 10月 15 19:20:58 anson-MR26 asterisk[80345]: [Oct 15 19:20:58] ERROR[80345]: loader.c:2249 load_modules: cdr_pgsql declined to load. 10月 15 19:20:58 anson-MR26 asterisk[80345]: [Oct 15 19:20:58] ERROR[80345]: loader.c:2249 load_modules: cel_sqlite3_custom declined to load. 10月 15 19:20:58 anson-MR26 asterisk[80345]: [Oct 15 19:20:58] ERROR[80345]: loader.c:2249 load_modules: cdr_sqlite3_custom declined to load. 10月 15 19:20:58 anson-MR26 asterisk[80345]: [Oct 15 19:20:58] ERROR[80345]: loader.c:2249 load_modules: chan_unistim declined to load. 10月 15 19:20:58 anson-MR26 asterisk[80345]: [Oct 15 19:20:58] ERROR[80345]: loader.c:2249 load_modules: pbx_dundi declined to load. 10月 15 19:20:58 anson-MR26 asterisk[80345]: [Oct 15 19:20:58] ERROR[80345]: loader.c:2249 load_modules: res_hep_rtcp declined to load. 10月 15 19:20:58 anson-MR26 asterisk[80345]: [Oct 15 19:20:58] ERROR[80345]: loader.c:2249 load_modules: res_hep_pjsip declined to load. 10月 15 19:20:58 anson-MR26 asterisk[80345]: Asterisk Ready. 10月 15 19:20:58 anson-MR26 systemd[1]: Started Asterisk PBX.anson@anson-MR26:/etc/asterisk$ sudo asterisk -r Asterisk 16.2.1~dfsg-2ubuntu1, Copyright (C) 1999 - 2018, Digium, Inc. and others. Created by Mark Spencer <markster@digium.com> Asterisk comes with ABSOLUTELY NO WARRANTY; type 'core show warranty' for details. This is free software, with components licensed under the GNU General Public License version 2 and other licenses; you are welcome to redistribute it under certain conditions. Type 'core show license' for details. ========================================================================= Running as user 'asterisk' Running under group 'asterisk' Connected to Asterisk 16.2.1~dfsg-2ubuntu1 currently running on anson-MR26 (pid = 80345)到这里, 可以开始打开sipdroid, 分别使用 9001 和 9002 账号密码进行设置并拨号.测试的结果是: 可以拨号对方也响铃, 但接通后, 没有音频, 原因未知miniSIPServer实用的SIP服务器 miniSIPServerUbuntu下的miniSIPServer下载DEB包, 装好依赖, 如QT5之类的, 再按文档执行:anson@anson-MR26:/opt/sipserver$ /opt/sipserver/minisipserver-cli 2021-10-15 21:05:25 | STUN server: 192.168.43.175:3478 2021-10-15 21:05:25 | STUN server: 192.168.43.175:3479 2021-10-15 21:05:25 | SIP server address (ipv4) is '192.168.43.175' 2021-10-15 21:05:25 | SIP server address (ipv6) is '2409:8954:e6a8:5977:1a27:a2b:7834:2c19' 2021-10-15 21:05:25 | SIP server UDP port is 5060 2021-10-15 21:05:25 | SIP server TCP port is 5060 2021-10-15 21:05:25 | HTTP server is running at port 8080, default password is '2C98487E501ABBF3'. 2021-10-15 21:05:25 | All data are stored in '/home/anson/.minisipserver'. 2021-10-15 21:05:25 | This version is 'V38 (5 clients) build 20210923, linux'. 2021-10-15 21:05:25 | Server is ready now.通过打印信息, 可以访问管理页面:SIP server web system 登陆信息中的随机密码即可进入.默认配置了100, 101, 102 三个账号, 对于测试来讲足够了.实测, 可以拨号语音!
平台RK3128 + Android 7.1目标1.使用Launcher32.显示状态栏和导航栏3.把TvSettings替换为Settings原图:最终效果:1. 模块整理主要是增删一些编译模块, 如, 删除TvSettings, 加上Settingsdevice/rockchip/common/tv/tv_base.mkdevice/rockchip/rk312x/device.mkvendor/rockchip/common/apps/apps.mk删除模块: RKTvLauncher MediaCenter TvProvider TvSettings rkmcapp-armeabi-v7a-debug增加: Launcher3 RKVideoPlayer RkExplorer2. Launcher3Launcher3编译不出来, 检查下这几个OVERLAY将对应的模块从配置中删除, 或直接注释掉../vendor/rockchip/common/apps/RockVRHome/Android.mk:LOCAL_OVERRIDES_PACKAGES := Launcher3 ./vendor/rockchip/common/apps/RKTvLauncher/Android.mk:#LOCAL_OVERRIDES_PACKAGES := Launcher3 ./vendor/rockchip/common/apps/MediaCenter/Android.mk:LOCAL_OVERRIDES_PACKAGES := Launcher3 ./vendor/rockchip/common/apps/itvlauncher/Android.mk:LOCAL_OVERRIDES_PACKAGES := Launcher3 ./vendor/rockchip/common/apps/ChangeLedStatus/Android.mk:LOCAL_OVERRIDES_PACKAGES := Launcher3Launcher3 启动不了1.am start -a android.intent.action.MAIN 不出现选择列表主要原因是系统初始化未完成, 仅能显示android:directBootAware属性的APP, 这个后面再说2.am start -n com.android.launcher3/.Launcher 崩溃, 且LOG很少1970-01-01 08:01:06.113 1039-1113/com.android.launcher3 W/WallpaperManager: WallpaperService not running 1970-01-01 08:01:06.121 1039-1113/com.android.launcher3 E/AndroidRuntime: FATAL EXCEPTION: pool-1-thread-2 Process: com.android.launcher3, PID: 1039 DeadSystemException: The system died; earlier logs will point to the root cause3.安装第三方NovaLauncher一样不能正常启动.2和3是由于缺少壁纸服务导致, 解决方法有两种.修改frameworks/base/services/java/com/android/server/SystemServer.javaif (!disableNonCoreServices/* && context.getResources().getBoolean( R.bool.config_enableWallpaperService)*/) { traceBeginAndSlog("StartWallpaperManagerService"); mSystemServiceManager.startService(WALLPAPER_SERVICE_CLASS); Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER); }修改配置: device/rockchip/common/tv/overlay/frameworks/base/core/res/res/values/config.xml <bool name="config_enableWallpaperService">true</bool>无法使用其它桌面: RKTvLauncher优先级设置为2, 高于Launcher3rk3128_box:/ # dumpsys package com.rockchips.android.leanbacklauncher Activity Resolver Table: Non-Data Actions: android.intent.action.MAIN: cc04bd7 com.rockchips.android.leanbacklauncher/.MainActivity filter 5b7e55d Action: "android.intent.action.MAIN" Category: "android.intent.category.HOME" Category: "android.intent.category.DEFAULT" mPriority=2, mHasPartialTypes=false AutoVerify=false 445fcc4 com.rockchips.android.leanbacklauncher/.DummyActivity filter ce29ea0 Action: "android.intent.action.MAIN" Category: "android.intent.category.LEANBACK_LAUNCHER" AutoVerify=false com.rockchips.android.leanbacklauncher.SETTINGS: 86887ad com.rockchips.android.leanbacklauncher/.settings.HomeScreenSettingsActivity filter a1d2ed2 Action: "com.rockchips.android.leanbacklauncher.SETTINGS" Category: "android.intent.category.DEFAULT" AutoVerify=false aa6aae2 com.rockchips.android.leanbacklauncher/.settings.FullScreenSettingsActivity filter b1d1ba3 Action: "com.rockchips.android.leanbacklauncher.SETTINGS" Category: "android.intent.category.DEFAULT" AutoVerify=false如上mPriority=2解决这个问题, 可以删除RkTvLauncher 或提高 Launcher3的优先级.3. 卡Android动画原因: 在服务启动完成的后, 执行**startHomeActivityLocked中, 找不到Activity:ActivityManagerService.javastartHomeActivityLocked -> Slog.wtf(TAG, "No home screen found for " + intent, new Throwable());PackageManagerService.java//没有返回对应的Launcher组件. PackageManagerService.resolveIntent同样的, 和android:directBootAware有关系, 在MID的SDK中, 正常流程下, 这时候会启动设置中的FallbackHome而在BOX的SDK中, Settings 中FallbackHome被删除了HOME属性, 导致启动后找不到Home…缺少了<category android:name="android.intent.category.HOME" />加上即可<!-- Triggered when user-selected home app isn't encryption aware --> <activity android:name=".FallbackHome" android:excludeFromRecents="true" android:screenOrientation="nosensor" android:theme="@style/FallbackHome"> <intent-filter android:priority="-1000"> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.HOME" /> <category android:name="android.intent.category.DEFAULT" /> </intent-filter> </activity>4. SystemUI在BOX中, 状态栏和导航栏是不显示的, 修改以下代码让它显示出来:修改组件,使用PhoneStatusBar: device/rockchip/common/tv/overlay/frameworks/base/packages/SystemUI/res/values/config.xml<string name="config_statusBarComponent" translatable="false">com.android.systemui.statusbar.phone.PhoneStatusBar</string>修改代码关于BOX的判断: frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/SystemBars.javadiff --git a/frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/SystemBars.java b/frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/SystemBars.java old mode 100644 new mode 100755 index da6265d..e8c6d84 --- a/frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/SystemBars.java +++ b/frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/SystemBars.java @@ -87,9 +87,9 @@ public class SystemBars extends SystemUI implements ServiceMonitor.Callbacks { private void createStatusBarFromConfig() { if (DEBUG) Log.d(TAG, "createStatusBarFromConfig"); String clsName = mContext.getString(R.string.config_statusBarComponent); - if ("box".equals(SystemProperties.get("ro.target.product", "tablet"))){ + /*if ("box".equals(SystemProperties.get("ro.target.product", "tablet"))){ clsName = "com.android.systemui.statusbar.tv.TvStatusBar"; - } + }*/ if (clsName == null || clsName.length() == 0) { throw andLog("No status bar component configured", null); }修改布局高度:device/rockchip/common/tv/overlay/frameworks/base/core/res/res/values/dimens.xml<resources> <!-- Height of the status bar --> <dimen name="status_bar_height">24dp</dimen> <!-- Height of the bottom navigation / system bar --> <dimen name="navigation_bar_height">48dp</dimen> <!-- Height of the bottom navigation bar in landscape --> <dimen name="navigation_bar_height_landscape">48dp</dimen> <!-- Width of the navigation bar when it is placed vertically on the screen --> <dimen name="navigation_bar_width">42dp</dimen> </resources>修改显示位置 frameworks/base/services/core/java/com/android/server/policy/PhoneWindowManager.javadiff --git a/frameworks/base/services/core/java/com/android/server/policy/PhoneWindowManager.java b/frameworks/base/services/core/java/com/android/server/policy/PhoneWindowManager.java index 7dfc835..dd737ce 100755 --- a/frameworks/base/services/core/java/com/android/server/policy/PhoneWindowManager.java +++ b/frameworks/base/services/core/java/com/android/server/policy/PhoneWindowManager.java @@ -2088,7 +2088,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { int longSizeDp = longSize * DisplayMetrics.DENSITY_DEFAULT / density; // Allow the navigation bar to move on non-square small devices (phones). - mNavigationBarCanMove = width != height && shortSizeDp < 600; + mNavigationBarCanMove = false;// width != height && shortSizeDp < 600; mHasNavigationBar = res.getBoolean(com.android.internal.R.bool.config_showNavigationBar); @@ -4524,6 +4524,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { } private int navigationBarPosition(int displayWidth, int displayHeight, int displayRotation) { + if(true)return NAV_BAR_BOTTOM; if (mNavigationBarCanMove && displayWidth > displayHeight) { if (displayRotation == Surface.ROTATION_270) { return NAV_BAR_LEFT; @@ -8270,6 +8271,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { pw.print(" mForceClearedSystemUiFlags=0x"); pw.println(Integer.toHexString(mForceClearedSystemUiFlags)); } + pw.print(" mHasNavigationBar="); pw.print(mHasNavigationBar); if (mLastFocusNeedsMenu) { pw.print(prefix); pw.print("mLastFocusNeedsMenu="); pw.println(mLastFocusNeedsMenu);5. 壁纸默认使用黑背景图片device/rockchip/common/tv/overlay/frameworks/base/core/res/res/drawable-nodpi/default_wallpaper.png6. 扩展1.若不使用Settings的FallbackHome 而 直接使用Launcher3 开机, 需要做以下修改diff --git a/packages/apps/Launcher3/Android.mk b/packages/apps/Launcher3/Android.mk old mode 100644 new mode 100755 diff --git a/packages/apps/Launcher3/AndroidManifest.xml b/packages/apps/Launcher3/AndroidManifest.xml old mode 100644 new mode 100755 index 6c5990d..7816dfb --- a/packages/apps/Launcher3/AndroidManifest.xml +++ b/packages/apps/Launcher3/AndroidManifest.xml @@ -52,6 +52,7 @@ <application android:backupAgent="com.android.launcher3.LauncherBackupAgent" android:fullBackupOnly="true" + android:directBootAware="true" android:fullBackupContent="@xml/backupscheme" android:hardwareAccelerated="true" android:icon="@mipmap/ic_launcher_home" diff --git a/packages/apps/Launcher3/src/com/android/launcher3/LauncherAppWidgetHost.java b/packages/apps/Launcher3/src/com/android/launcher3/LauncherAppWidgetHost.java old mode 100644 new mode 100755 index d3e5350..a4c5a3b --- a/packages/apps/Launcher3/src/com/android/launcher3/LauncherAppWidgetHost.java +++ b/packages/apps/Launcher3/src/com/android/launcher3/LauncherAppWidgetHost.java @@ -62,7 +62,7 @@ public class LauncherAppWidgetHost extends AppWidgetHost { // have been established by this point, and we will end up populating the // widgets upon bind anyway. See issue 14255011 for more context. } else { - throw new RuntimeException(e); + //throw new RuntimeException(e); } } } diff --git a/packages/apps/Launcher3/src/com/android/launcher3/QsbContainerView.java b/packages/apps/Launcher3/src/com/android/launcher3/QsbContainerView.java index ffed8fc..39170d9 100755 --- a/packages/apps/Launcher3/src/com/android/launcher3/QsbContainerView.java +++ b/packages/apps/Launcher3/src/com/android/launcher3/QsbContainerView.java @@ -249,7 +249,10 @@ public class QsbContainerView extends FrameLayout { public static AppWidgetProviderInfo getSearchWidgetProvider(Context context) { SearchManager searchManager = (SearchManager) context.getSystemService(Context.SEARCH_SERVICE); - ComponentName searchComponent = searchManager.getGlobalSearchActivity(); + ComponentName searchComponent = null; + try{ + searchComponent = searchManager.getGlobalSearchActivity(); + }catch(Exception ignore){} if (searchComponent == null) return null; String providerPkg = searchComponent.getPackageName();主要解决1.AMS找不到Home导致卡动画问题.2.启动Launcher3后自身崩溃问题, LOG如下:Launcher3 崩溃1970-01-01 08:01:05.414 2963-2963/com.android.launcher3 D/AndroidRuntime: Shutting down VM 1970-01-01 08:01:05.417 2963-2963/com.android.launcher3 E/AndroidRuntime: FATAL EXCEPTION: main Process: com.android.launcher3, PID: 2963 java.lang.RuntimeException: Unable to start activity ComponentInfo{com.android.launcher3/com.android.launcher3.Launcher}: java.lang.RuntimeException: java.lang.IllegalStateException: User 0 must be unlocked for widgets to be available at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2666) at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2727) at android.app.ActivityThread.-wrap12(ActivityThread.java) at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1478) at android.os.Handler.dispatchMessage(Handler.java:102) at android.os.Looper.loop(Looper.java:154) at android.app.ActivityThread.main(ActivityThread.java:6121) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:912) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:802) Caused by: java.lang.RuntimeException: java.lang.IllegalStateException: User 0 must be unlocked for widgets to be available at com.android.launcher3.LauncherAppWidgetHost.startListening(LauncherAppWidgetHost.java:65) at com.android.launcher3.Launcher.onCreate(Launcher.java:417) at android.app.Activity.performCreate(Activity.java:6709) at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1118) at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2619) at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2727) at android.app.ActivityThread.-wrap12(ActivityThread.java) at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1478) at android.os.Handler.dispatchMessage(Handler.java:102) at android.os.Looper.loop(Looper.java:154) at android.app.ActivityThread.main(ActivityThread.java:6121) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:912) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:802) Caused by: java.lang.IllegalStateException: User 0 must be unlocked for widgets to be available at android.os.Parcel.readException(Parcel.java:1692) at android.os.Parcel.readException(Parcel.java:1637) at com.android.internal.appwidget.IAppWidgetService$Stub$Proxy.startListening(IAppWidgetService.java:494) at android.appwidget.AppWidgetHost.startListening(AppWidgetHost.java:191) at com.android.launcher3.LauncherAppWidgetHost.startListening(LauncherAppWidgetHost.java:56) at com.android.launcher3.Launcher.onCreate(Launcher.java:417) at android.app.Activity.performCreate(Activity.java:6709) at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1118) at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2619) at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2727) at android.app.ActivityThread.-wrap12(ActivityThread.java) at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1478) at android.os.Handler.dispatchMessage(Handler.java:102) at android.os.Looper.loop(Looper.java:154) at android.app.ActivityThread.main(ActivityThread.java:6121) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:912) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:802)frameworks/base/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java "User " + userId + " must be unlocked for widgets to be available");
平台Android 7.1 + RK3288概述从Android 4.4开始支持沉浸式全屏体验,在沉浸式全屏模式下,状态栏、 虚拟按键动态隐藏,应用可以使用完整的屏幕空间,按照 Google 的说法,给用户一种 “身临其境” 的体验。增加了 IMMERSIVE 和 IMMERSIVE_STICKY 标记,可以用这两个标记与 SYSTEM_UI_FLAG_HIDE_NAVIGATION 和 SYSTEM_UI_FLAG_FULLSCREEN 一起使用, 来实现沉 浸模式。全屏的是通过隐藏状态栏和导航栏实现, 服务之间的交互如下:关键函数frameworks/base/services/core/java/com/android/server/policy/PhoneWindowManager.java//顾名思义, 状态栏的控制器与导航栏的控制器, 设置显示/隐藏, 或临时显示都需要它 private final StatusBarController mStatusBarController = new StatusBarController(); private final BarController mNavigationBarController = new BarController("NavigationBar", View.NAVIGATION_BAR_TRANSIENT, View.NAVIGATION_BAR_UNHIDE, View.NAVIGATION_BAR_TRANSLUCENT, StatusBarManager.WINDOW_NAVIGATION_BAR, WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION, View.NAVIGATION_BAR_TRANSPARENT); //WindowManagerService调用 @Override public int adjustSystemUiVisibilityLw(int visibility) { mStatusBarController.adjustSystemUiVisibilityLw(mLastSystemUiFlags, visibility); mNavigationBarController.adjustSystemUiVisibilityLw(mLastSystemUiFlags, visibility); // Reset any bits in mForceClearingStatusBarVisibility that // are now clear. mResettingSystemUiFlags &= visibility; // Clear any bits in the new visibility that are currently being // force cleared, before reporting it. return visibility & ~mResettingSystemUiFlags & ~mForceClearedSystemUiFlags; } //更新FLAG用, 比如, 会获取APP的指定FLAG, 再与前面的控制器交互并更新当前的系统FLAG private int updateSystemUiVisibilityLw() { // If there is no window focused, there will be nobody to handle the events // anyway, so just hang on in whatever state we're in until things settle down. WindowState winCandidate = mFocusedWindow != null ? mFocusedWindow : mTopFullscreenOpaqueWindowState; if (winCandidate == null) { return 0; } if (winCandidate.getAttrs().token == mImmersiveModeConfirmation.getWindowToken()) { // The immersive mode confirmation should never affect the system bar visibility, // otherwise it will unhide the navigation bar and hide itself. winCandidate = isStatusBarKeyguard() ? mStatusBar : mTopFullscreenOpaqueWindowState; if (winCandidate == null) { return 0; } } final WindowState win = winCandidate; if ((win.getAttrs().privateFlags & PRIVATE_FLAG_KEYGUARD) != 0 && mHideLockScreen == true) { // We are updating at a point where the keyguard has gotten // focus, but we were last in a state where the top window is // hiding it. This is probably because the keyguard as been // shown while the top window was displayed, so we want to ignore // it here because this is just a very transient change and it // will quickly lose focus once it correctly gets hidden. return 0; } int tmpVisibility = PolicyControl.getSystemUiVisibility(win, null) & ~mResettingSystemUiFlags & ~mForceClearedSystemUiFlags; if (mForcingShowNavBar && win.getSurfaceLayer() < mForcingShowNavBarLayer) { tmpVisibility &= ~PolicyControl.adjustClearableFlags(win, View.SYSTEM_UI_CLEARABLE_FLAGS); } final int fullscreenVisibility = updateLightStatusBarLw(0 /* vis */, mTopFullscreenOpaqueWindowState, mTopFullscreenOpaqueOrDimmingWindowState); final int dockedVisibility = updateLightStatusBarLw(0 /* vis */, mTopDockedOpaqueWindowState, mTopDockedOpaqueOrDimmingWindowState); mWindowManagerFuncs.getStackBounds(HOME_STACK_ID, mNonDockedStackBounds); mWindowManagerFuncs.getStackBounds(DOCKED_STACK_ID, mDockedStackBounds); final int visibility = updateSystemBarsLw(win, mLastSystemUiFlags, tmpVisibility); final int diff = visibility ^ mLastSystemUiFlags; final int fullscreenDiff = fullscreenVisibility ^ mLastFullscreenStackSysUiFlags; final int dockedDiff = dockedVisibility ^ mLastDockedStackSysUiFlags; final boolean needsMenu = win.getNeedsMenuLw(mTopFullscreenOpaqueWindowState); if (diff == 0 && fullscreenDiff == 0 && dockedDiff == 0 && mLastFocusNeedsMenu == needsMenu && mFocusedApp == win.getAppToken() && mLastNonDockedStackBounds.equals(mNonDockedStackBounds) && mLastDockedStackBounds.equals(mDockedStackBounds)) { return 0; } mLastSystemUiFlags = visibility; mLastFullscreenStackSysUiFlags = fullscreenVisibility; mLastDockedStackSysUiFlags = dockedVisibility; mLastFocusNeedsMenu = needsMenu; mFocusedApp = win.getAppToken(); final Rect fullscreenStackBounds = new Rect(mNonDockedStackBounds); final Rect dockedStackBounds = new Rect(mDockedStackBounds); mHandler.post(new Runnable() { @Override public void run() { StatusBarManagerInternal statusbar = getStatusBarManagerInternal(); if (statusbar != null) { //传递给SystemUI statusbar.setSystemUiVisibility(visibility, fullscreenVisibility, dockedVisibility, 0xffffffff, fullscreenStackBounds, dockedStackBounds, win.toString()); statusbar.topAppWindowChanged(needsMenu); } } }); return diff; } private int updateLightStatusBarLw(int vis, WindowState opaque, WindowState opaqueOrDimming) { WindowState statusColorWin = isStatusBarKeyguard() && !mHideLockScreen ? mStatusBar : opaqueOrDimming; if (statusColorWin != null) { if (statusColorWin == opaque) { // If the top fullscreen-or-dimming window is also the top fullscreen, respect // its light flag. vis &= ~View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR; vis |= PolicyControl.getSystemUiVisibility(statusColorWin, null) & View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR; } else if (statusColorWin != null && statusColorWin.isDimming()) { // Otherwise if it's dimming, clear the light flag. vis &= ~View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR; } } return vis; } private int updateSystemBarsLw(WindowState win, int oldVis, int vis) { final boolean dockedStackVisible = mWindowManagerInternal.isStackVisible(DOCKED_STACK_ID); final boolean freeformStackVisible = mWindowManagerInternal.isStackVisible(FREEFORM_WORKSPACE_STACK_ID); final boolean resizing = mWindowManagerInternal.isDockedDividerResizing(); // We need to force system bars when the docked stack is visible, when the freeform stack // is visible but also when we are resizing for the transitions when docked stack // visibility changes. mForceShowSystemBars = dockedStackVisible || freeformStackVisible || resizing; final boolean forceOpaqueStatusBar = mForceShowSystemBars && !mForceStatusBarFromKeyguard; // apply translucent bar vis flags WindowState fullscreenTransWin = isStatusBarKeyguard() && !mHideLockScreen ? mStatusBar : mTopFullscreenOpaqueWindowState; vis = mStatusBarController.applyTranslucentFlagLw(fullscreenTransWin, vis, oldVis); vis = mNavigationBarController.applyTranslucentFlagLw(fullscreenTransWin, vis, oldVis); final int dockedVis = mStatusBarController.applyTranslucentFlagLw( mTopDockedOpaqueWindowState, 0, 0); final boolean fullscreenDrawsStatusBarBackground = (drawsSystemBarBackground(mTopFullscreenOpaqueWindowState) && (vis & View.STATUS_BAR_TRANSLUCENT) == 0) || forcesDrawStatusBarBackground(mTopFullscreenOpaqueWindowState); final boolean dockedDrawsStatusBarBackground = (drawsSystemBarBackground(mTopDockedOpaqueWindowState) && (dockedVis & View.STATUS_BAR_TRANSLUCENT) == 0) || forcesDrawStatusBarBackground(mTopDockedOpaqueWindowState); // prevent status bar interaction from clearing certain flags int type = win.getAttrs().type; boolean statusBarHasFocus = type == TYPE_STATUS_BAR; if (statusBarHasFocus && !isStatusBarKeyguard()) { int flags = View.SYSTEM_UI_FLAG_FULLSCREEN | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_IMMERSIVE | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY | View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR; if (mHideLockScreen) { flags |= View.STATUS_BAR_TRANSLUCENT | View.NAVIGATION_BAR_TRANSLUCENT; } vis = (vis & ~flags) | (oldVis & flags); } if (fullscreenDrawsStatusBarBackground && dockedDrawsStatusBarBackground) { vis |= View.STATUS_BAR_TRANSPARENT; vis &= ~View.STATUS_BAR_TRANSLUCENT; } else if ((!areTranslucentBarsAllowed() && fullscreenTransWin != mStatusBar) || forceOpaqueStatusBar) { vis &= ~(View.STATUS_BAR_TRANSLUCENT | View.STATUS_BAR_TRANSPARENT); } vis = configureNavBarOpacity(vis, dockedStackVisible, freeformStackVisible, resizing); // update status bar boolean immersiveSticky = (vis & View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY) != 0; final boolean hideStatusBarWM = mTopFullscreenOpaqueWindowState != null && (PolicyControl.getWindowFlags(mTopFullscreenOpaqueWindowState, null) & WindowManager.LayoutParams.FLAG_FULLSCREEN) != 0; final boolean hideStatusBarSysui = (vis & View.SYSTEM_UI_FLAG_FULLSCREEN) != 0; final boolean hideNavBarSysui = (vis & View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) != 0; final boolean transientStatusBarAllowed = mStatusBar != null && (statusBarHasFocus || (!mForceShowSystemBars && (hideStatusBarWM || (hideStatusBarSysui && immersiveSticky)))); final boolean transientNavBarAllowed = mNavigationBar != null && !mForceShowSystemBars && hideNavBarSysui && immersiveSticky; final long now = SystemClock.uptimeMillis(); final boolean pendingPanic = mPendingPanicGestureUptime != 0 && now - mPendingPanicGestureUptime <= PANIC_GESTURE_EXPIRATION; if (pendingPanic && hideNavBarSysui && !isStatusBarKeyguard() && mKeyguardDrawComplete) { // The user performed the panic gesture recently, we're about to hide the bars, // we're no longer on the Keyguard and the screen is ready. We can now request the bars. mPendingPanicGestureUptime = 0; mStatusBarController.showTransient(); if (!isNavBarEmpty(vis)) { mNavigationBarController.showTransient(); } } final boolean denyTransientStatus = mStatusBarController.isTransientShowRequested() && !transientStatusBarAllowed && hideStatusBarSysui; final boolean denyTransientNav = mNavigationBarController.isTransientShowRequested() && !transientNavBarAllowed; if (denyTransientStatus || denyTransientNav || mForceShowSystemBars) { // clear the clearable flags instead clearClearableFlagsLw(); vis &= ~View.SYSTEM_UI_CLEARABLE_FLAGS; } final boolean immersive = (vis & View.SYSTEM_UI_FLAG_IMMERSIVE) != 0; immersiveSticky = (vis & View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY) != 0; final boolean navAllowedHidden = immersive || immersiveSticky; if (hideNavBarSysui && !navAllowedHidden && windowTypeToLayerLw(win.getBaseType()) > windowTypeToLayerLw(TYPE_INPUT_CONSUMER)) { // We can't hide the navbar from this window otherwise the input consumer would not get // the input events. vis = (vis & ~View.SYSTEM_UI_FLAG_HIDE_NAVIGATION); } vis = mStatusBarController.updateVisibilityLw(transientStatusBarAllowed, oldVis, vis); // update navigation bar boolean oldImmersiveMode = isImmersiveMode(oldVis); boolean newImmersiveMode = isImmersiveMode(vis); if (win != null && oldImmersiveMode != newImmersiveMode) { final String pkg = win.getOwningPackage(); mImmersiveModeConfirmation.immersiveModeChangedLw(pkg, newImmersiveMode, isUserSetupComplete(), isNavBarEmpty(win.getSystemUiVisibility())); } vis = mNavigationBarController.updateVisibilityLw(transientNavBarAllowed, oldVis, vis); return vis; }frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java //SystemUI中处理由PWS传过来的FLAG. @Override // CommandQueue public void setSystemUiVisibility(int vis, int fullscreenStackVis, int dockedStackVis, int mask, Rect fullscreenStackBounds, Rect dockedStackBounds) { final int oldVal = mSystemUiVisibility; final int newVal = (oldVal&~mask) | (vis&mask); final int diff = newVal ^ oldVal; if (true) Log.d(TAG, String.format( "setSystemUiVisibility vis=%s mask=%s oldVal=%s newVal=%s diff=%s", Integer.toHexString(vis), Integer.toHexString(mask), Integer.toHexString(oldVal), Integer.toHexString(newVal), Integer.toHexString(diff))); boolean sbModeChanged = false; if (diff != 0) { mSystemUiVisibility = newVal; // update low profile if ((diff & View.SYSTEM_UI_FLAG_LOW_PROFILE) != 0) { setAreThereNotifications(); } // ready to unhide if ((vis & View.STATUS_BAR_UNHIDE) != 0) { mSystemUiVisibility &= ~View.STATUS_BAR_UNHIDE; mNoAnimationOnNextBarModeChange = true; } // update status bar mode final int sbMode = computeBarMode(oldVal, newVal, mStatusBarView.getBarTransitions(), View.STATUS_BAR_TRANSIENT, View.STATUS_BAR_TRANSLUCENT, View.STATUS_BAR_TRANSPARENT); // update navigation bar mode final int nbMode = mNavigationBarView == null ? -1 : computeBarMode( oldVal, newVal, mNavigationBarView.getBarTransitions(), View.NAVIGATION_BAR_TRANSIENT, View.NAVIGATION_BAR_TRANSLUCENT, View.NAVIGATION_BAR_TRANSPARENT); sbModeChanged = sbMode != -1; final boolean nbModeChanged = nbMode != -1; boolean checkBarModes = false; if (sbModeChanged && sbMode != mStatusBarMode) { mStatusBarMode = sbMode; checkBarModes = true; } if (nbModeChanged && nbMode != mNavigationBarMode) { mNavigationBarMode = nbMode; checkBarModes = true; } if (checkBarModes) { checkBarModes(); } if (sbModeChanged || nbModeChanged) { // update transient bar autohide if (mStatusBarMode == MODE_SEMI_TRANSPARENT || mNavigationBarMode == MODE_SEMI_TRANSPARENT) { scheduleAutohide(); } else { cancelAutohide(); } } if ((vis & View.NAVIGATION_BAR_UNHIDE) != 0) { mSystemUiVisibility &= ~View.NAVIGATION_BAR_UNHIDE; } //变更新, 传递新的FLAG给WMS. // send updated sysui visibility to window manager notifyUiVisibilityChanged(mSystemUiVisibility); } mLightStatusBarController.onSystemUiVisibilityChanged(fullscreenStackVis, dockedStackVis, mask, fullscreenStackBounds, dockedStackBounds, sbModeChanged, mStatusBarMode); }frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.java@Override public void statusBarVisibilityChanged(int visibility) { Log.d(TAG, "statusBarVisibilityChanged 0x" + Integer.toHexString(visibility)); if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.STATUS_BAR) != PackageManager.PERMISSION_GRANTED) { throw new SecurityException("Caller does not hold permission " + android.Manifest.permission.STATUS_BAR); } synchronized (mWindowMap) { mLastStatusBarVisibility = visibility; //mPolicy == PhoneWindowManager visibility = mPolicy.adjustSystemUiVisibilityLw(visibility); updateStatusBarVisibilityLocked(visibility); } }一些常量frameworks/base/core/java/android/view/View.javapublic static final int STATUS_BAR_UNHIDE = 0x10000000; public static final int NAVIGATION_BAR_UNHIDE = 0x20000000; public static final int STATUS_BAR_TRANSIENT = 0x04000000; public static final int NAVIGATION_BAR_TRANSIENT = 0x08000000; public static final int SYSTEM_UI_FLAG_HIDE_NAVIGATION = 0x00000002; public static final int SYSTEM_UI_FLAG_IMMERSIVE = 0x00000800; public static final int SYSTEM_UI_FLAG_IMMERSIVE_STICKY= 0x00001000; public static final int NAVIGATION_BAR_TRANSPARENT = 0x00008000; public static final int SYSTEM_UI_FLAG_LAYOUT_STABLE = 0x00000100; public static final int SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION = 0x00000200; public static final int SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN = 0x00000400; public static final int STATUS_BAR_TRANSPARENT = 0x0000008;如前面在PhoneStatusBar中打印statusBarVisibilityChanged 0x的16进制字符串.如:隐藏->显示:D/PhoneStatusBar: setSystemUiVisibility vis=3c009f0f mask=ffffffff oldVal=9f0f newVal=3c009f0f diff=3c000000显示->隐藏:D/PhoneStatusBar: setSystemUiVisibility vis=9f0f mask=ffffffff oldVal=c009f0f newVal=9f0f diff=c000000一些干货3秒的自动隐藏时间:frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java //3秒后自动隐藏 private static final long AUTOHIDE_TIMEOUT_MS = 3000; private void scheduleAutohide() { cancelAutohide(); mHandler.postDelayed(mAutohide, AUTOHIDE_TIMEOUT_MS); }隐藏/显示动画首先找出动画是SystemUI自己执行还是由WMS去执行, 答案是WMS, 看下打印出来的堆栈信息:2021-09-08 18:44:51.850 467-1102/system_process W/System.err: at com.android.server.wm.WindowStateAnimator.setAnimation(WindowStateAnimator.java:275) 2021-09-08 18:44:51.850 467-1102/system_process W/System.err: at com.android.server.wm.WindowStateAnimator.setAnimation(WindowStateAnimator.java:296) 2021-09-08 18:44:51.852 467-1102/system_process W/System.err: at com.android.server.wm.WindowStateAnimator.applyAnimationLocked(WindowStateAnimator.java:1938) 2021-09-08 18:44:51.852 467-1102/system_process W/System.err: at com.android.server.wm.WindowState.showLw(WindowState.java:1926) 2021-09-08 18:44:51.852 467-1102/system_process W/System.err: at com.android.server.wm.WindowState.showLw(WindowState.java:1890) 2021-09-08 18:44:51.852 467-1102/system_process W/System.err: at com.android.server.policy.BarController.setBarShowingLw(BarController.java:151) 2021-09-08 18:44:51.853 467-1102/system_process W/System.err: at com.android.server.policy.BarController.adjustSystemUiVisibilityLw(BarController.java:116) 2021-09-08 18:44:51.853 467-1102/system_process W/System.err: at com.android.server.policy.PhoneWindowManager.adjustSystemUiVisibilityLw(PhoneWindowManager.java:4124) 2021-09-08 18:44:51.853 467-1102/system_process W/System.err: at com.android.server.wm.WindowManagerService.statusBarVisibilityChanged(WindowManagerService.java:10951)动画资源函数有对状态栏和导航栏对应进出资源的判断.frameworks/base/services/core/java/com/android/server/policy/PhoneWindowManager.java/** {@inheritDoc} */ @Override public int selectAnimationLw(WindowState win, int transit) { if (PRINT_ANIM) Log.i(TAG, "selectAnimation in " + win + ": transit=" + transit); if (win == mStatusBar) { boolean isKeyguard = (win.getAttrs().privateFlags & PRIVATE_FLAG_KEYGUARD) != 0; if (transit == TRANSIT_EXIT || transit == TRANSIT_HIDE) { return isKeyguard ? -1 : R.anim.dock_top_exit; } else if (transit == TRANSIT_ENTER || transit == TRANSIT_SHOW) { return isKeyguard ? -1 : R.anim.dock_top_enter; } } else if (win == mNavigationBar) { if (win.getAttrs().windowAnimations != 0) { return 0; } // This can be on either the bottom or the right or the left. if (mNavigationBarPosition == NAV_BAR_BOTTOM) { if (transit == TRANSIT_EXIT || transit == TRANSIT_HIDE) { if (isKeyguardShowingAndNotOccluded()) { return R.anim.dock_bottom_exit_keyguard; } else { return R.anim.dock_bottom_exit; } } else if (transit == TRANSIT_ENTER || transit == TRANSIT_SHOW) { return R.anim.dock_bottom_enter; } } else if (mNavigationBarPosition == NAV_BAR_RIGHT) { if (transit == TRANSIT_EXIT || transit == TRANSIT_HIDE) { return R.anim.dock_right_exit; } else if (transit == TRANSIT_ENTER || transit == TRANSIT_SHOW) { return R.anim.dock_right_enter; } } else if (mNavigationBarPosition == NAV_BAR_LEFT) { if (transit == TRANSIT_EXIT || transit == TRANSIT_HIDE) { return R.anim.dock_left_exit; } else if (transit == TRANSIT_ENTER || transit == TRANSIT_SHOW) { return R.anim.dock_left_enter; } } } else if (win.getAttrs().type == TYPE_DOCK_DIVIDER) { return selectDockedDividerAnimationLw(win, transit); } if (transit == TRANSIT_PREVIEW_DONE) { if (win.hasAppShownWindows()) { if (PRINT_ANIM) Log.i(TAG, "**** STARTING EXIT"); return com.android.internal.R.anim.app_starting_exit; } } else if (win.getAttrs().type == TYPE_DREAM && mDreamingLockscreen && transit == TRANSIT_ENTER) { // Special case: we are animating in a dream, while the keyguard // is shown. We don't want an animation on the dream, because // we need it shown immediately with the keyguard animating away // to reveal it. return -1; } return 0; }在后续一些定制修改中, 强制修改了FLAG让状态栏一直显示.在全屏应用下, 系统会再次使StatusBar隐藏, 原因在于layout完成后,会再确认顶层应用窗口是否全屏, 并对应设置Window是否显示, 此过程无动画2021-09-09 18:05:05.679 449-562/system_process W/System.err: at com.android.server.policy.BarController.updateStateLw(BarController.java:194) 2021-09-09 18:05:05.680 449-562/system_process W/System.err: at com.android.server.policy.BarController.setBarShowingLw(BarController.java:166) 2021-09-09 18:05:05.680 449-562/system_process W/System.err: at com.android.server.policy.PhoneWindowManager.finishPostLayoutPolicyLw(PhoneWindowManager.java:5511) 2021-09-09 18:05:05.680 449-562/system_process W/System.err: at com.android.server.wm.WindowSurfacePlacer.applySurfaceChangesTransaction(WindowSurfacePlacer.java:674) 2021-09-09 18:05:05.680 449-562/system_process W/System.err: at com.android.server.wm.WindowSurfacePlacer.performSurfacePlacementInner(WindowSurfacePlacer.java:320) 2021-09-09 18:05:05.680 449-562/system_process W/System.err: at com.android.server.wm.WindowSurfacePlacer.performSurfacePlacementLoop(WindowSurfacePlacer.java:235) 2021-09-09 18:05:05.680 449-562/system_process W/System.err: at com.android.server.wm.WindowSurfacePlacer.performSurfacePlacement(WindowSurfacePlacer.java:184)finishPostLayoutPolicyLw中调用setBarShowingLw, 把状态栏隐藏了, 若需保持状态栏一直显示, 需处理这部分代码mStatusBarController.setBarShowingLw(false);多使用dumpsysdumpsys window//实时查看服务的变量状态 mOrientationSensorEnabled=true mOverscanScreen=(0,0) 1920x1080 mRestrictedOverscanScreen=(0,0) 1920x1080 mUnrestrictedScreen=(0,0) 1920x1080 mRestrictedScreen=(0,0) 1920x1080 mStableFullscreen=(0,0)-(1920,1024) mStable=(0,24)-(1920,1024) mSystem=(0,0)-(1920,1080) mCur=(0,24)-(1920,1080) mContent=(0,24)-(1920,1080) mVoiceContent=(0,24)-(1920,1080) mDock=(0,24)-(1920,1080) //状态栏被mStatusBarController.setBarShowingLw(false);隐藏时: Window #7 Window{1633372 u0 StatusBar}: mDisplayId=0 stackId=0 mSession=Session{f3c2053 644:u0a10018} mClient=android.os.BinderProxy@236987d mOwnerUid=10018 mShowToOwnerOnly=false package=com.android.systemui appop=NONE mAttrs=WM.LayoutParams{(0,0)(fillx24) taskId=-1 gr=#30 sim=#10 ty=2000 fl=#81840048 fmt=-3 vsysui=0x600} Requested w=1920 h=24 mLayoutSeq=85 mPolicyVisibility=false mPolicyVisibilityAfterAnim=false mAppOpVisibility=true mAttachedHidden=false mPermanentlyHidden=false mHasSurface=true mShownPosition=[0,0] isReadyForDisplay()=false hasSavedSurface()=false mWindowRemovalAllowed=false WindowStateAnimator{7a4071f StatusBar}: Surface: shown=false layer=161000 alpha=1.0 rect=(0.0,0.0) 1920.0 x 24.0 ---------------------------------- //状态栏显示时 Window #5 Window{1633372 u0 StatusBar}: mDisplayId=0 stackId=0 mSession=Session{f3c2053 644:u0a10018} mClient=android.os.BinderProxy@236987d mOwnerUid=10018 mShowToOwnerOnly=false package=com.android.systemui appop=NONE mAttrs=WM.LayoutParams{(0,0)(fillx24) taskId=-1 gr=#30 sim=#10 ty=2000 fl=#81840048 fmt=-3 vsysui=0x600} Requested w=1920 h=24 mLayoutSeq=163 mHasSurface=true mShownPosition=[0,0] isReadyForDisplay()=true hasSavedSurface()=false mWindowRemovalAllowed=false WindowStateAnimator{7a4071f StatusBar}: mAnimating=false mLocalAnimating=false mAnimationIsEntrance=true mAnimation=null mStackClip=1 Surface: shown=true layer=161000 alpha=1.0 rect=(0.0,0.0) 1920.0 x 24.0 ------------------------------------------------------ //状态栏隐藏动画过程 Window #5 Window{16f510e u0 StatusBar}: mDisplayId=0 stackId=0 mSession=Session{5e171f4 632:u0a10018} mClient=android.os.BinderProxy@3e87b09 mOwnerUid=10018 mShowToOwnerOnly=false package=com.android.systemui appop=NONE mAttrs=WM.LayoutParams{(0,0)(fillx24) taskId=-1 gr=#30 sim=#10 ty=2000 fl=#81840048 fmt=-3 vsysui=0x600} Requested w=1920 h=24 mLayoutSeq=69 mPolicyVisibility=true mPolicyVisibilityAfterAnim=false mAppOpVisibility=true mAttachedHidden=false mPermanentlyHidden=false mHasSurface=true mShownPosition=[0,-4] isReadyForDisplay()=true hasSavedSurface()=false mWindowRemovalAllowed=false WindowStateAnimator{2214d2c StatusBar}: mAnimating=true mLocalAnimating=true mAnimationIsEntrance=false mAnimation=android.view.animation.AnimationSet@5de858d mStackClip=0 XForm: has=true hasLocal=true {alpha=1.0 matrix=[1.0, 0.0, 0.0][0.0, 1.0, -3.5060544][0.0, 0.0, 1.0]} Surface: shown=true layer=161000 alpha=1.0 rect=(0.0,-4.0) 1920.0 x 24.0 mGlobalScale=1.0 mDsDx=1.0 mDtDx=0.0 mDsDy=0.0 mDtDy=1.0修改了状态栏FLAG后, 窗口布局(大小/位置)不正确可以看看这个函数, 多打打df, vf, cf …的值frameworks/base/services/core/java/com/android/server/policy/PhoneWindowManager.javapublic void layoutWindowLw(WindowState win, WindowState attached, int width, int height) { // We've already done the navigation bar and status bar. If the status bar can receive // input, we need to layout it again to accomodate for the IME window. if ((win == mStatusBar && !canReceiveInput(win)) || win == mNavigationBar) { return; } final WindowManager.LayoutParams attrs = win.getAttrs(); final boolean isDefaultDisplay = win.isDefaultDisplay(); final boolean needsToOffsetInputMethodTarget = isDefaultDisplay && (win == mLastInputMethodTargetWindow && mLastInputMethodWindow != null); if (needsToOffsetInputMethodTarget) { if (DEBUG_LAYOUT) Slog.i(TAG, "Offset ime target window by the last ime window state"); offsetInputMethodWindowLw(mLastInputMethodWindow); } final int fl = PolicyControl.getWindowFlags(win, attrs); final int pfl = attrs.privateFlags; final int sim = attrs.softInputMode; final int sysUiFl = PolicyControl.getSystemUiVisibility(win, null); final Rect pf = mTmpParentFrame; final Rect df = mTmpDisplayFrame; final Rect of = mTmpOverscanFrame; final Rect cf = mTmpContentFrame; final Rect vf = mTmpVisibleFrame; final Rect dcf = mTmpDecorFrame; final Rect sf = mTmpStableFrame; //省略N行代码..... if (DEBUG_LAYOUT) Slog.v(TAG, "Compute frame " + attrs.getTitle() + ": sim=#" + Integer.toHexString(sim) + " attach=" + attached + " type=" + attrs.type + String.format(" flags=0x%08x", fl) + " pf=" + pf.toShortString() + " df=" + df.toShortString() + " of=" + of.toShortString() + " cf=" + cf.toShortString() + " vf=" + vf.toShortString() + " dcf=" + dcf.toShortString() + " sf=" + sf.toShortString() + " osf=" + (osf == null ? "null" : osf.toShortString())); win.computeFrameLw(pf, df, of, cf, vf, dcf, sf, osf); }扩展Android 沉浸式状态栏
平台Ubuntu 20.04(x64)Buildroot 2021.02Qt 5.15.2关于Buildrootbuildroot使用介绍The Buildroot user manual通过buildroot+qemu搭建ARM-Linux虚拟开发环境目标简单描述:1.buildroot的下载编译过程2.支持QT的配置说明及步骤模拟环境在开始编译之前, 查询了一些资料, 对模拟器的支持如下:ubuntu下使用qemu-system-arm模拟arm环境Buildroot and QEMU – the quickest receipe for your own Linux$ sudo apt-get install qemu-system-arm $ qemu-system-arm --version QEMU emulator version 4.2.1 (Debian 1:4.2-3ubuntu6.14) Copyright (c) 2003-2019 Fabrice Bellard and the QEMU Project developers而在成功编译完成后, 生成了output/images/start-qemu.sh, 并且可以直接运行上面的步骤是否可以省略?Buildroot下载解压Downloads$ll buildroot-2021.02.tar.gz -rw-rw-r-- 1 anson anson 6797744 3月 15 11:37 buildroot-2021.02.tar.gz #解压后(仅参考,其中已包含一些编译后的文件) $ll drwxrwxr-x 16 anson anson 4096 3月 16 15:14 ./ drwxrwxr-x 6 anson anson 4096 3月 15 11:37 ../ drwxrwxr-x 2 anson anson 4096 3月 7 05:16 arch/ drwxrwxr-x 69 anson anson 4096 3月 7 05:16 board/ drwxrwxr-x 22 anson anson 4096 3月 7 05:16 boot/ -rw-rw-r-- 1 anson anson 416183 3月 7 05:16 CHANGES -rw-r--r-- 1 anson anson 108253 3月 16 15:13 .config -rw-rw-r-- 1 anson anson 28043 3月 7 05:16 Config.in -rw-rw-r-- 1 anson anson 126066 3月 7 05:16 Config.in.legacy -rw-r--r-- 1 anson anson 108095 3月 16 14:55 .config.old drwxrwxr-x 2 anson anson 20480 3月 7 05:16 configs/ -rw-r--r-- 1 anson anson 98729 3月 16 15:14 ..config.tmp -rw-rw-r-- 1 anson anson 18767 3月 7 05:16 COPYING -rw-rw-r-- 1 anson anson 1198 3月 7 05:16 .defconfig -rw-rw-r-- 1 anson anson 68473 3月 7 05:16 DEVELOPERS drwxr-xr-x 56 anson anson 4096 3月 16 15:52 dl/ drwxr-xr-x 5 anson anson 4096 3月 7 05:24 docs/ -rw-rw-r-- 1 anson anson 96 3月 7 05:16 .flake8 drwxrwxr-x 19 anson anson 4096 3月 7 05:16 fs/ -rw-rw-r-- 1 anson anson 125 3月 7 05:16 .gitignore -rw-rw-r-- 1 anson anson 557 3月 7 05:16 .gitlab-ci.yml drwxrwxr-x 2 anson anson 4096 3月 7 05:16 linux/ -rw-rw-r-- 1 anson anson 45530 3月 7 05:16 Makefile -rw-rw-r-- 1 anson anson 2292 3月 7 05:16 Makefile.legacy drwxrwxr-x 6 anson anson 4096 3月 16 16:45 output/ drwxrwxr-x 2495 anson anson 69632 3月 7 05:16 package/ -rw-rw-r-- 1 anson anson 1079 3月 7 05:16 README drwxrwxr-x 13 anson anson 4096 3月 7 05:16 support/ drwxrwxr-x 3 anson anson 4096 3月 7 05:16 system/ drwxrwxr-x 5 anson anson 4096 3月 7 05:16 toolchain/ drwxrwxr-x 3 anson anson 4096 3月 7 05:16 utils/Buildroot配置编译# 加载默认ARM模拟配置 $ make qemu_arm_vexpress_defconfig #编译 $ make# 编译完成的一些LOG Filesystem UUID: 68f5438c-6ab0-4b9b-9dbf-ec8856ea50ed Superblock backups stored on blocks: 8193, 24577, 40961, 57345 Allocating group tables: done Writing inode tables: done Copying files into the device: done Writing superblocks and filesystem accounting information: done ln -snf /home/anson/codes/buildroot-2021.02/output/host/arm-buildroot-linux-uclibcgnueabihf/sysroot /home/anson/codes/buildroot-2021.02/output/staging >>> Executing post-image script board/qemu/post-image.sh运行模拟环境$ output/images/start-qemu.sh VNC server running on ::1:5900 Booting Linux on physical CPU 0x0 Linux version 5.10.7 (anson@server4) (arm-buildroot-linux-uclibcgnueabihf-gcc.br_real (Buildroot 2021.02) 9.3.0, GNU ld (GNU Binutils) 2.35.2) #1 SMP Tue Mar 16 16:37:25 CST 2021 CPU: ARMv7 Processor [410fc090] revision 0 (ARMv7), cr=10c5387d CPU: PIPT / VIPT nonaliasing data cache, VIPT nonaliasing instruction cache OF: fdt: Machine model: V2P-CA9 Memory policy: Data cache writeback Reserved memory: created DMA memory pool at 0x4c000000, size 8 MiB OF: reserved mem: initialized node vram@4c000000, compatible id shared-dma-pool cma: Reserved 16 MiB at 0x6f000000 Zone ranges: Normal [mem 0x0000000060000000-0x000000006fffffff] Movable zone start for each node Early memory node ranges node 0: [mem 0x0000000060000000-0x000000006fffffff] Initmem setup node 0 [mem 0x0000000060000000-0x000000006fffffff] CPU: All CPU(s) started in SVC mode. percpu: Embedded 19 pages/cpu s46156 r8192 d23476 u77824 Built 1 zonelists, mobility grouping on. Total pages: 65024 Kernel command line: console=ttyAMA0,115200 rootwait root=/dev/mmcblk0 printk: log_buf_len individual max cpu contribution: 4096 bytes printk: log_buf_len total cpu_extra contributions: 12288 bytes printk: log_buf_len min size: 16384 bytes printk: log_buf_len: 32768 bytes printk: early log buf free: 14792(90%) Dentry cache hash table entries: 32768 (order: 5, 131072 bytes, linear) Inode-cache hash table entries: 16384 (order: 4, 65536 bytes, linear) mem auto-init: stack:off, heap alloc:off, heap free:off Memory: 231920K/262144K available (7168K kernel code, 583K rwdata, 1748K rodata, 1024K init, 181K bss, 13840K reserved, 16384K cma-reserved) SLUB: HWalign=64, Order=0-3, MinObjects=0, CPUs=4, Nodes=1 rcu: Hierarchical RCU implementation. rcu: RCU event tracing is enabled. rcu: RCU restricting CPUs from NR_CPUS=8 to nr_cpu_ids=4. rcu: RCU calculated value of scheduler-enlistment delay is 10 jiffies. rcu: Adjusting geometry for rcu_fanout_leaf=16, nr_cpu_ids=4 NR_IRQS: 16, nr_irqs: 16, preallocated irqs: 16 GIC CPU mask not found - kernel will fail to boot. GIC CPU mask not found - kernel will fail to boot. L2C: platform modifies aux control register: 0x02020000 -> 0x02420000 L2C: DT/platform modifies aux control register: 0x02020000 -> 0x02420000 L2C-310 enabling early BRESP for Cortex-A9 L2C-310 full line of zeros enabled for Cortex-A9 L2C-310 dynamic clock gating disabled, standby mode disabled L2C-310 cache controller enabled, 8 ways, 128 kB L2C-310: CACHE_ID 0x410000c8, AUX_CTRL 0x46420001 random: get_random_bytes called from start_kernel+0x384/0x538 with crng_init=0 sched_clock: 32 bits at 24MHz, resolution 41ns, wraps every 89478484971ns clocksource: arm,sp804: mask: 0xffffffff max_cycles: 0xffffffff, max_idle_ns: 1911260446275 ns Failed to initialize '/bus@4000000/motherboard/iofpga@7,00000000/timer@12000': -22 smp_twd: clock not found -2 Console: colour dummy device 80x30 Calibrating local timer... 99.83MHz. Calibrating delay loop... 427.62 BogoMIPS (lpj=2138112) pid_max: default: 32768 minimum: 301 Mount-cache hash table entries: 1024 (order: 0, 4096 bytes, linear) Mountpoint-cache hash table entries: 1024 (order: 0, 4096 bytes, linear) CPU: Testing write buffer coherency: ok CPU0: Spectre v2: using BPIALL workaround CPU0: thread -1, cpu 0, socket 0, mpidr 80000000 Setting up static identity map for 0x60100000 - 0x60100060 rcu: Hierarchical SRCU implementation. smp: Bringing up secondary CPUs ... smp: Brought up 1 node, 1 CPU SMP: Total of 1 processors activated (427.62 BogoMIPS). CPU: All CPU(s) started in SVC mode. devtmpfs: initialized VFP support v0.3: implementor 41 architecture 3 part 30 variant 9 rev 0 clocksource: jiffies: mask: 0xffffffff max_cycles: 0xffffffff, max_idle_ns: 19112604462750000 ns futex hash table entries: 1024 (order: 4, 65536 bytes, linear) NET: Registered protocol family 16 DMA: preallocated 256 KiB pool for atomic coherent allocations cpuidle: using governor ladder hw-breakpoint: debug architecture 0x4 unsupported. Serial: AMBA PL011 UART driver irq: type mismatch, failed to map hwirq-75 for interrupt-controller@1e001000! SCSI subsystem initialized usbcore: registered new interface driver usbfs usbcore: registered new interface driver hub usbcore: registered new device driver usb Advanced Linux Sound Architecture Driver Initialized. clocksource: Switched to clocksource arm,sp804 NET: Registered protocol family 2 tcp_listen_portaddr_hash hash table entries: 512 (order: 0, 6144 bytes, linear) TCP established hash table entries: 2048 (order: 1, 8192 bytes, linear) TCP bind hash table entries: 2048 (order: 2, 16384 bytes, linear) TCP: Hash tables configured (established 2048 bind 2048) UDP hash table entries: 256 (order: 1, 8192 bytes, linear) UDP-Lite hash table entries: 256 (order: 1, 8192 bytes, linear) NET: Registered protocol family 1 RPC: Registered named UNIX socket transport module. RPC: Registered udp transport module. RPC: Registered tcp transport module. RPC: Registered tcp NFSv4.1 backchannel transport module. hw perfevents: enabled with armv7_cortex_a9 PMU driver, 5 counters available workingset: timestamp_bits=30 max_order=16 bucket_order=0 squashfs: version 4.0 (2009/01/31) Phillip Lougher jffs2: version 2.2. (NAND) © 2001-2006 Red Hat, Inc. 9p: Installing v9fs 9p2000 file system support io scheduler mq-deadline registered io scheduler kyber registered i2c i2c-0: Added multiplexed i2c bus 2 physmap-flash 40000000.flash: physmap platform flash device: [mem 0x40000000-0x43ffffff] 40000000.flash: Found 2 x16 devices at 0x0 in 32-bit bank. Manufacturer ID 0x000000 Chip ID 0x000000 Intel/Sharp Extended Query Table at 0x0031 Using buffer write method physmap-flash 40000000.flash: physmap platform flash device: [mem 0x44000000-0x47ffffff] 40000000.flash: Found 2 x16 devices at 0x0 in 32-bit bank. Manufacturer ID 0x000000 Chip ID 0x000000 Intel/Sharp Extended Query Table at 0x0031 Using buffer write method Concatenating MTD devices: (0): "40000000.flash" (1): "40000000.flash" into device "40000000.flash" physmap-flash 48000000.psram: physmap platform flash device: [mem 0x48000000-0x49ffffff] libphy: Fixed MDIO Bus: probed libphy: smsc911x-mdio: probed smsc911x 4e000000.ethernet eth0: MAC Address: 52:54:00:12:34:56 isp1760 4f000000.usb: bus width: 32, oc: digital isp1760 4f000000.usb: NXP ISP1760 USB Host Controller isp1760 4f000000.usb: new USB bus registered, assigned bus number 1 isp1760 4f000000.usb: Scratch test failed. isp1760 4f000000.usb: can't setup: -19 isp1760 4f000000.usb: USB bus 1 deregistered usbcore: registered new interface driver usb-storage ledtrig-cpu: registered to indicate activity on CPUs usbcore: registered new interface driver usbhid usbhid: USB HID core driver NET: Registered protocol family 17 9pnet: Installing 9P2000 support oprofile: using arm/armv7-ca9 Registering SWP/SWPB emulation handler aaci-pl041 10004000.aaci: ARM AC'97 Interface PL041 rev0 at 0x10004000, irq 32 aaci-pl041 10004000.aaci: FIFO 512 entries mmci-pl18x 10005000.mmci: Got CD GPIO mmci-pl18x 10005000.mmci: Got WP GPIO mmci-pl18x 10005000.mmci: mmc0: PL181 manf 41 rev0 at 0x10005000 irq 33,34 (pio) 10009000.uart: ttyAMA0 at MMIO 0x10009000 (irq = 37, base_baud = 0) is a PL011 rev1 printk: console [ttyAMA0] enabled 1000a000.uart: ttyAMA1 at MMIO 0x1000a000 (irq = 38, base_baud = 0) is a PL011 rev1 1000b000.uart: ttyAMA2 at MMIO 0x1000b000 (irq = 39, base_baud = 0) is a PL011 rev1 1000c000.uart: ttyAMA3 at MMIO 0x1000c000 (irq = 40, base_baud = 0) is a PL011 rev1 rtc-pl031 10017000.rtc: registered as rtc0 rtc-pl031 10017000.rtc: setting system clock to 2021-03-16T09:37:19 UTC (1615887439) mmc0: new SD card at address 4567 drm-clcd-pl111 1001f000.clcd: assigned reserved memory node vram@4c000000 drm-clcd-pl111 1001f000.clcd: using device-specific reserved memory drm-clcd-pl111 1001f000.clcd: core tile graphics present drm-clcd-pl111 1001f000.clcd: this device will be deactivated drm-clcd-pl111 1001f000.clcd: Versatile Express init failed - -19 mmcblk0: mmc0:4567 QEMU! 64.0 MiB drm-clcd-pl111 10020000.clcd: DVI muxed to daughterboard 1 (core tile) CLCD input: AT Raw Set 2 keyboard as /devices/platform/bus@4000000/bus@4000000:motherboard/bus@4000000:motherboard:iofpga@7,00000000/10006000.kmi/serio0/input/input0 drm-clcd-pl111 10020000.clcd: initializing Versatile Express PL111 drm-clcd-pl111 10020000.clcd: found bridge on endpoint 0 drm-clcd-pl111 10020000.clcd: Using non-panel bridge [drm] Initialized pl111 1.0.0 20170317 for 10020000.clcd on minor 0 Console: switching to colour frame buffer device 128x48 drm-clcd-pl111 10020000.clcd: [drm] fb0: pl111drmfb frame buffer device ALSA device list: #0: ARM AC'97 Interface PL041 rev0 at 0x10004000, irq 32 input: ImExPS/2 Generic Explorer Mouse as /devices/platform/bus@4000000/bus@4000000:motherboard/bus@4000000:motherboard:iofpga@7,00000000/10007000.kmi/serio1/input/input2 random: fast init done EXT4-fs (mmcblk0): mounted filesystem without journal. Opts: (null) VFS: Mounted root (ext4 filesystem) readonly on device 179:0. devtmpfs: mounted Freeing unused kernel memory: 1024K Run /sbin/init as init process random: crng init done EXT4-fs (mmcblk0): re-mounted. Opts: (null) ext4 filesystem being remounted at / supports timestamps until 2038 (0x7fffffff) Starting syslogd: OK Starting klogd: OK Running sysctl: OK Saving random seed: OK Starting network: Generic PHY 4e000000.ethernet-ffffffff:01: attached PHY driver [Generic PHY] (mii_bus:phy_addr=4e000000.ethernet-ffffffff:01, irq=POLL) smsc911x 4e000000.ethernet eth0: SMSC911x/921x identified at 0x908b0000, IRQ: 30 udhcpc: started, v1.33.0 udhcpc: sending discover udhcpc: sending select for 10.0.2.15 udhcpc: lease of 10.0.2.15 obtained, lease time 86400 deleting routers adding dns 10.0.2.3 OK Initializing postgresql data base... The files belonging to this database system will be owned by user "postgres". This user must also own the server process. The database cluster will be initialized with locale "C". The default database encoding has accordingly been set to "SQL_ASCII". The default text search configuration will be set to "english". Data page checksums are disabled. fixing permissions on existing directory /var/lib/pgsql ... ok creating subdirectories ... ok selecting dynamic shared memory implementation ... posix selecting default max_connections ... 100 selecting default shared_buffers ... 128MB selecting default time zone ... UTC creating configuration files ... ok running bootstrap script ... 2021-03-16 09:38:36.554 UTC [137] FATAL: could not write to file "pg_wal/xlogtemp.137": No space left on device child process exited with exit code 1 initdb: removing contents of data directory "/var/lib/pgsql" pg_ctl: database system initialization failed done Starting postgresql: pg_ctl: directory "/var/lib/pgsql" is not a database cluster directory OK Welcome to Buildroot buildroot login: root # ls -la / total 25 drwxr-xr-x 18 root root 1024 Mar 16 08:45 . drwxr-xr-x 18 root root 1024 Mar 16 08:45 .. drwxr-xr-x 2 root root 2048 Mar 16 08:45 bin drwxr-xr-x 7 root root 2900 Mar 16 09:37 dev drwxr-xr-x 6 root root 1024 Mar 16 08:45 etc drwxr-xr-x 3 root root 1024 Mar 16 08:45 lib lrwxrwxrwx 1 root root 3 Mar 16 07:25 lib32 -> lib lrwxrwxrwx 1 root root 11 Mar 16 07:39 linuxrc -> bin/busybox drwx------ 2 root root 12288 Mar 16 08:45 lost+found drwxr-xr-x 2 root root 1024 Mar 6 21:16 media drwxr-xr-x 2 root root 1024 Mar 6 21:16 mnt drwxr-xr-x 2 root root 1024 Mar 6 21:16 opt dr-xr-xr-x 106 root root 0 Mar 16 09:37 proc drwx------ 2 root root 1024 Mar 16 09:40 root drwxr-xr-x 3 root root 160 Mar 16 09:37 run drwxr-xr-x 2 root root 1024 Mar 16 08:45 sbin dr-xr-xr-x 12 root root 0 Mar 16 09:37 sys drwxrwxrwt 2 root root 80 Mar 16 09:37 tmp drwxr-xr-x 6 root root 1024 Mar 16 08:45 usr drwxr-xr-x 4 root root 1024 Mar 16 08:45 var一些问题:尝试运行menuconfig报错:$ make menuconfig /usr/bin/gcc -I/usr/include/ncursesw -DCURSES_LOC="<curses.h>" -DNCURSES_WIDECHAR=1 -DLOCALE -I/home/anson/work/codes/buildroot-2021.02/output/build/buildroot-config -DCONFIG_=\"\" /home/anson/work/codes/buildroot-2021.02/output/build/buildroot-config/mconf.o /home/anson/work/codes/buildroot-2021.02/output/build/buildroot-config/zconf.tab.o /home/anson/work/codes/buildroot-2021.02/output/build/buildroot-config/lxdialog/checklist.o /home/anson/work/codes/buildroot-2021.02/output/build/buildroot-config/lxdialog/util.o /home/anson/work/codes/buildroot-2021.02/output/build/buildroot-config/lxdialog/inputbox.o /home/anson/work/codes/buildroot-2021.02/output/build/buildroot-config/lxdialog/textbox.o /home/anson/work/codes/buildroot-2021.02/output/build/buildroot-config/lxdialog/yesno.o /home/anson/work/codes/buildroot-2021.02/output/build/buildroot-config/lxdialog/menubox.o -o /home/anson/work/codes/buildroot-2021.02/output/build/buildroot-config/mconf /usr/bin/ld: /home/anson/work/codes/buildroot-2021.02/output/build/buildroot-config/mconf.o: in function `show_help': mconf.c:(.text+0x1862): undefined reference to `stdscr' /usr/bin/ld: mconf.c:(.text+0x186e): undefined reference to `stdscr' /usr/bin/ld: /home/anson/work/codes/buildroot-2021.02/output/build/buildroot-config/lxdialog/checklist.o: in function `print_item': checklist.c:(.text+0x8a): undefined reference to `wattrset' /usr/bin/ld: checklist.c:(.text+0xa0): undefined reference to `wmove' ....省略.... /usr/bin/ld: /home/anson/work/codes/buildroot-2021.02/output/build/buildroot-config/lxdialog/menubox.o:menubox.c:(.text+0x1300): more undefined references to `delwin' follow collect2: error: ld returned 1 exit status make[2]: *** [Makefile.br:28: mconf] Error 1 rm /home/anson/work/codes/buildroot-2021.02/output/build/buildroot-config/zconf.tab.c make[1]: *** [Makefile:969: /home/anson/work/codes/buildroot-2021.02/output/build/buildroot-config/mconf] Error 2 make: *** [Makefile:84: _all] Error 2解决 Solution for “make menuconfig” Error in Linux PC# 无效 #$ sudo apt-get install build-essentials $ sudo apt-get install libncurses5 libncurses5-dev以下为PC内存的问题, 此问题忽略$ make cc: internal compiler error: Segmentation fault signal terminated program as Please submit a full bug report, with preprocessed source if appropriate. See <file:///usr/share/doc/gcc-9/README.Bugs> for instructions. make[4]: *** [Makefile:488: lucnum2_ui.lo] Error 1 make[4]: *** Waiting for unfinished jobs.... libtool: compile: /usr/bin/gcc -DHAVE_CONFIG_H -I. -I.. -D__GMP_WITHIN_GMP -I.. -I/home/anson/work/codes/buildroot-2021.02/output/host/include -O2 -I/home/anson/work/codes/buildroot-2021.02/output/host/include -c mul_si.c -fPIC -DPIC -o .libs/mul_si.o libtool: compile: /usr/bin/gcc -DHAVE_CONFIG_H -I. -I.. -D__GMP_WITHIN_GMP -I.. -I/home/anson/work/codes/buildroot-2021.02/output/host/include -O2 -I/home/anson/work/codes/buildroot-2021.02/output/host/include -c n_pow_ui.c -fPIC -DPIC -o .libs/n_pow_ui.o libtool: compile: /usr/bin/gcc -DHAVE_CONFIG_H -I. -I.. -D__GMP_WITHIN_GMP -I.. -I/home/anson/work/codes/buildroot-2021.02/output/host/include -O2 -I/home/anson/work/codes/buildroot-2021.02/output/host/include -c mul_ui.c -fPIC -DPIC -o .libs/mul_ui.o make[3]: *** [Makefile:997: all-recursive] Error 1 make[2]: *** [Makefile:787: all] Error 2 make[1]: *** [package/pkg-generic.mk:250: /home/anson/work/codes/buildroot-2021.02/output/build/host-gmp-6.2.1/.stamp_built] Error 2 make: *** [Makefile:84: _all] Error 2make[2]: /home/rohit/workplace/rp/buildroot/output/host/usr/bin/arm-buildroot-linux-uclibcgnueabihf-gccGetting arm-buildroot-linux-uclibcgnueabihf-gcc: Command not found如何支持 Qt前面编译出来的系统, 并没有对QT的支持, 仅仅用于验证开发环境的一些尝试make menuconfig默认的模拟配置并不支持勾选QT选项*** Qt5 needs host g++ >= 5.0, and a toolchain w/ gcc >= 5.0, wchar, NPTL, C++, dynam ***估计是问题有些太低级, 所以, 不管GOOGLE还是BAIDU,没有文章可以给出很好的答案来说明, 如何让QT选项可以勾选.解决:修改Toolchain后, 终于可以用QT的选项了:重新编译# 清除, 不清除编译会有报错 $ make clean # 重新编译 $ make编译完成后, 可以找到qmake$ output/build/qt5base-5.15.2/bin/qmake -v QMake version 3.1 Using Qt version 5.15.2 in /home/anson/codes/buildroot-2021.02/output/host/arm-buildroot-linux-uclibcgnueabi/sysroot/usr/lib也可以找到相应的examples, 如 analogclockoutput/build/qt5base-5.15.2/examples/widgets/widgets$ ll total 116 drwxr-xr-x 27 anson anson 4096 11月 13 01:24 ./ drwxr-xr-x 25 anson anson 4096 11月 13 01:24 ../ drwxr-xr-x 2 anson anson 4096 11月 13 01:24 analogclock/ drwxr-xr-x 2 anson anson 4096 11月 13 01:24 calculator/ drwxr-xr-x 2 anson anson 4096 11月 13 01:24 calendarwidget/ drwxr-xr-x 2 anson anson 4096 11月 13 01:24 charactermap/ drwxr-xr-x 2 anson anson 4096 11月 13 01:24 codeeditor/ drwxr-xr-x 2 anson anson 4096 11月 13 01:24 digitalclock/ drwxr-xr-x 2 anson anson 4096 11月 13 01:24 elidedlabel/ drwxr-xr-x 2 anson anson 4096 11月 13 01:24 groupbox/ drwxr-xr-x 3 anson anson 4096 11月 13 01:24 icons/ drwxr-xr-x 2 anson anson 4096 11月 13 01:24 imageviewer/ drwxr-xr-x 2 anson anson 4096 11月 13 01:24 lineedits/ drwxr-xr-x 2 anson anson 4096 11月 13 01:24 mousebuttons/ drwxr-xr-x 2 anson anson 4096 11月 13 01:24 movie/ -rw-r--r-- 1 anson anson 477 10月 27 16:02 README drwxr-xr-x 2 anson anson 4096 11月 13 01:24 scribble/ drwxr-xr-x 2 anson anson 4096 11月 13 01:24 shapedclock/ drwxr-xr-x 2 anson anson 4096 11月 13 01:24 sliders/ drwxr-xr-x 2 anson anson 4096 11月 13 01:24 spinboxes/ drwxr-xr-x 3 anson anson 4096 11月 13 01:24 styles/ drwxr-xr-x 5 anson anson 4096 11月 13 01:24 stylesheet/ drwxr-xr-x 3 anson anson 4096 11月 13 01:24 tablet/ drwxr-xr-x 2 anson anson 4096 11月 13 01:24 tetrix/ drwxr-xr-x 3 anson anson 4096 11月 13 01:24 tooltips/ drwxr-xr-x 2 anson anson 4096 11月 13 01:24 validators/ -rw-r--r-- 1 anson anson 725 10月 27 16:02 widgets.pro drwxr-xr-x 2 anson anson 4096 11月 13 01:24 wiggly/ drwxr-xr-x 2 anson anson 4096 11月 13 01:24 windowflags/如何在Buildroot中编译Qt请参考:[哇酷网 whycan.cn]Buildroot成功后如何编译Qt应用程序尝试执行qmake生成Makefile文件时报错:失败的尝试 1buildroot-2021.02$ output/build/qt5base-5.15.2/bin/qmake output/build/qt5base-5.15.2/examples/widgets/widgets/analogclock/analogclock.pro Info: creating stash file /.qmake.stash /home/anson/codes/buildroot-2021.02/output/build/qt5base-5.15.2/mkspecs/features/toolchain.prf:73: Cannot write cache file /.qmake.stash: Permission denied Info: creating stash file /.qmake.stash /home/anson/codes/buildroot-2021.02/output/build/qt5base-5.15.2/mkspecs/features/toolchain.prf:73: Cannot write cache file /.qmake.stash: Permission denied Info: creating stash file /.qmake.stash /home/anson/codes/buildroot-2021.02/output/build/qt5base-5.15.2/mkspecs/features/toolchain.prf:73: Cannot write cache file /.qmake.stash: Permission denied Info: creating stash file /.qmake.stash /home/anson/codes/buildroot-2021.02/output/build/qt5base-5.15.2/mkspecs/features/toolchain.prf:73: Cannot write cache file /.qmake.stash: Permission denied Info: creating stash file /.qmake.stash /home/anson/codes/buildroot-2021.02/output/build/qt5base-5.15.2/mkspecs/features/toolchain.prf:76: Cannot write cache file /.qmake.stash: Permission denied Info: creating stash file /.qmake.stash /home/anson/codes/buildroot-2021.02/output/build/qt5base-5.15.2/mkspecs/features/toolchain.prf:409: Cannot write cache file /.qmake.stash: Permission denied Info: creating stash file /.qmake.stash /home/anson/codes/buildroot-2021.02/output/build/qt5base-5.15.2/mkspecs/features/toolchain.prf:411: Cannot write cache file /.qmake.stash: Permission denied Project ERROR: Unknown module(s) in QT: gui widgets失败的尝试 2output/build/qt5base-5.15.2/examples/widgets/widgets/analogclock$ /home/anson/codes/buildroot-2021.02/output/build/qt5base-5.15.2/bin/qmake analogclock.pro Project ERROR: Unknown module(s) in QT: gui widgets解决: 打开QT中gui->widgets配置重新编译# 清除, 不清除编译会有报错 $ make clean # 重新编译 $ make编译完成后, analogclock已经编译好了output/build/qt5base-5.15.2/examples/widgets/widgets/analogclock$ ll total 132 drwxr-xr-x 5 anson anson 4096 3月 16 16:51 ./ drwxr-xr-x 27 anson anson 4096 3月 16 16:33 ../ -rwxrwxr-x 1 anson anson 27180 3月 16 16:51 analogclock* -rw-r--r-- 1 anson anson 4675 10月 27 16:02 analogclock.cpp -rw-r--r-- 1 anson anson 2712 10月 27 16:02 analogclock.h -rw-r--r-- 1 anson anson 242 10月 27 16:02 analogclock.pro -rw-r--r-- 1 anson anson 2641 10月 27 16:02 main.cpp -rw-rw-r-- 1 anson anson 61743 3月 16 16:51 Makefile drwxrwxr-x 2 anson anson 4096 3月 16 16:51 .moc/ drwxrwxr-x 2 anson anson 4096 3月 16 16:51 .obj/ drwxrwxr-x 2 anson anson 4096 3月 16 16:51 .pch/尝试删除 analogclock Makefile .moc .obj .pch, 再执行qmake, 可以正常生成Makefile执行make, 生成analogclock—完结—参考Buildroot笔记buildroot使用介绍The Buildroot user manual通过buildroot+qemu搭建ARM-Linux虚拟开发环境ubuntu下使用qemu-system-arm模拟arm环境Buildroot and QEMU – the quickest receipe for your own LinuxGetting arm-buildroot-linux-uclibcgnueabihf-gcc: Command not foundSolution for “make menuconfig” Error in Linux PC[哇酷网 whycan.cn]Buildroot成功后如何编译Qt应用程序通过buildroot解决需要移植QT库的问题!!!!步骤详细,需要的拿走GCC_ARM_LINUX Downloads
平台Android 7.1 + AndroidStudio 4.1.2需求实现FTP客户端功能实现服务端: 客户使用pure-ftpd搭建了一个FTP服务器 (IP: 1.2.3.4)Ubuntu FTP服务器搭建参考:ubuntu下安装pure-ftpd记录# 安装 sudo apt-get install pure-ftpd装完后, 使用ftp连接, 并输入用户名密码, 即可访问FTP服务# 连接 ftp localhost Connected to localhost. 220---------- Welcome to Pure-FTPd [privsep] [TLS] ---------- 220-You are user number 1 of 50 allowed. 220-Local time is now 09:19. Server port: 21. 220-This is a private system - No anonymous login 220-IPv6 connections are also welcome on this server. 220 You will be disconnected after 15 minutes of inactivity. Name (localhost:anson): 331 User anson OK. Password required Password: 230 OK. Current directory is /home/anson Remote system type is UNIX. Using binary mode to transfer files. ftp> ls 200 PORT command successful 150 Connecting to port 46661 drwxr-xr-x 2 anson anson 4096 Feb 20 09:12 Desktop drwxr-xr-x 2 anson anson 4096 Dec 25 21:57 Documents drwxr-xr-x 5 anson anson 4096 Mar 3 16:05 Downloads drwxr-xr-x 2 anson anson 4096 Dec 25 21:57 Music drwxr-xr-x 5 anson anson 4096 Mar 3 14:12 Pictures drwxr-xr-x 2 anson anson 4096 Dec 25 21:57 Public drwxrwxr-x 4 anson anson 4096 Feb 19 17:16 StudioProjects drwxr-xr-x 2 anson anson 4096 Dec 25 21:57 Templates drwxr-xr-x 2 anson anson 4096 Feb 23 17:06 Videos#添加ftp用户组 sudo groupadd ftpgroup #添加虚拟用户 #sudo pure-pw useradd bbm -u anson -g ftpgroup -d /home/anson/Downloads/ftpbbm #> ERROR: You must give (non-root) uid and gid #添加FTP用户 sudo useradd ftp -g ftpgroup -d /home/anson/Downloads/ftp -s /sbin/nologin #添加虚拟用户 sudo pure-pw useradd bbm -u ftp -g ftpgroup -d /home/anson/Downloads/ftp/bbm sudo pure-pw mkdb #解决登陆问题 #530 Login authentication failed sudo ln -s /etc/pure-ftpd/conf/PureDB /etc/pure-ftpd/auth/PureDB #生启生效 sudo /etc/init.d/pure-ftpd restart上传失败# FTP目录权限问题 chown ftp:ftpgroup /home/anson/Downloads/ftp/bbm完成客户端:LINUX: ftp命令:ftp 1.2.3.4 Connected to 1.2.3.4 220---------- Welcome to Pure-FTPd [privsep] [TLS] ---------- 220-You are user number 1 of 50 allowed. 220-Local time is now 16:39. Server port: 21. 220-This is a private system - No anonymous login 220-IPv6 connections are also welcome on this server. 220 You will be disconnected after 15 minutes of inactivity. Name (1.2.3.4:user): bbm 331 User bbm OK. Password required Password: 230 OK. Current directory is / Remote system type is UNIX. Using binary mode to transfer files. ftp> ls 200 PORT command successful 150 Connecting to port 54375 lrwxrwxrwx 1 0 0 26 Mar 2 14:59 PureDB -> /etc/pure-ftpd/conf/PureDB drwxr-xr-x 2 0 0 4096 Mar 2 14:52 message drwxr-xr-x 2 0 0 4096 Mar 2 14:52 music drwxr-xr-x 2 0 0 4096 Mar 2 14:52 photo drwxr-xr-x 2 0 0 4096 Mar 2 14:56 video 226-Options: -l 226 5 matches total ftp> quit 221-Goodbye. You uploaded 0 and downloaded 0 kbytes. 221 Logout.Window + FlashFTP, 可以登陆, 但没有文件列表, 也报错FlashFXP 5.4.0 (build 3970)Support Forums https://www.flashfxp.com/forum/[15:24:49] Winsock 2.2 -- OpenSSL 1.1.0e 16 Feb 2017 [15:25:23] [R] 正在连接到 1.2.3.4 -> IP=1.2.3.4 PORT=21 [15:25:24] [R] 已连接到 1.2.3.4 [15:25:25] [R] 220---------- Welcome to Pure-FTPd [privsep] [TLS] ---------- [15:25:25] [R] 220-You are user number 2 of 50 allowed. [15:25:25] [R] 220-Local time is now 15:25. Server port: 21. [15:25:25] [R] 220-This is a private system - No anonymous login [15:25:25] [R] 220-IPv6 connections are also welcome on this server. [15:25:25] [R] 220 You will be disconnected after 15 minutes of inactivity. [15:25:25] [R] USER bbm [15:25:25] [R] 331 User bbm OK. Password required [15:25:25] [R] PASS (hidden) [15:25:25] [R] 230 OK. Current directory is / [15:25:25] [R] SYST [15:25:25] [R] 215 UNIX Type: L8 [15:25:25] [R] FEAT [15:25:25] [R] 211-Extensions supported: [15:25:25] [R] EPRT [15:25:25] [R] IDLE [15:25:25] [R] MDTM [15:25:25] [R] SIZE [15:25:25] [R] MFMT [15:25:25] [R] REST STREAM [15:25:25] [R] MLST type*;size*;sizd*;modify*;UNIX.mode*;UNIX.uid*;UNIX.gid*;unique*; [15:25:25] [R] MLSD [15:25:25] [R] AUTH TLS [15:25:25] [R] PBSZ [15:25:25] [R] PROT [15:25:25] [R] UTF8 [15:25:25] [R] TVFS [15:25:25] [R] ESTA [15:25:25] [R] PASV [15:25:25] [R] EPSV [15:25:25] [R] SPSV [15:25:25] [R] ESTP [15:25:25] [R] 211 End. [15:25:25] [R] OPTS UTF8 ON [15:25:25] [R] 200 OK, UTF-8 enabled [15:25:25] [R] PWD [15:25:25] [R] 257 "/" is your current location [15:25:25] [R] PASV [15:25:25] [R] 227 Entering Passive Mode (172,27,207,6,179,96) [15:25:25] [R] 正在打开数据连接 IP: 1.2.3.4 端口: 45920 [15:25:46] [R] 数据套接字错㿯查询到的一些资料(前面搭建的FTP服务器并未出现此问题, 仅记录 未尝试):开启阿里云linux下的pure-ftpd被动模式,解决flashfxp可连接但无法下载的问题linux系统宝塔控制面板下建立pure-ftpd用FlashFXP链接报错421以及530的解决办法Android[本文重心]实现的方法其实有很多, 以前用过ftp4j, 今天尝试使用Apache Commons NetApache Commons NetApache Commons Net 3.8.0 API下载 commons-net-3.8.0-bin.tar.gz解压:~/Downloads$ ll commons-net-3.8.0 total 876 drwxrwxr-x 4 anson anson 4096 3月 3 16:05 ./ drwxr-xr-x 5 anson anson 4096 3月 3 16:05 ../ drwxrwxr-x 4 anson anson 4096 3月 3 16:05 apidocs/ -rw-r--r-- 1 anson anson 307305 1月 22 2020 commons-net-3.8.0.jar -rw-r--r-- 1 anson anson 437325 1月 22 2020 commons-net-3.8.0-sources.jar -rw-r--r-- 1 anson anson 92684 1月 22 2020 commons-net-examples-3.8.0.jar -rw-r--r-- 1 anson anson 11358 1月 22 2020 LICENSE.txt -rw-r--r-- 1 anson anson 173 1月 22 2020 NOTICE.txt drwxrwxr-x 3 anson anson 4096 3月 3 16:05 org/ -rw-r--r-- 1 anson anson 5749 1月 22 2020 README.md -rw-r--r-- 1 anson anson 8785 1月 22 2020 RELEASE-NOTES.txt再把commons-net-3.8.0.jar加入的Studio项目信赖.import org.apache.commons.net.ftp.FTP; import org.apache.commons.net.ftp.FTPClient; import org.apache.commons.net.ftp.FTPFile; public class FtpClient extends Activity { final String TAG = "FtpClient"; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.ftp_client); new Thread(){ @Override public void run() { try { //创建和连接 FTPClient ftpClient = new FTPClient(); ftpClient.connect("1.2.3.4"); ftpClient.login("user", "12345678"); ftpClient.changeWorkingDirectory("/"); ftpClient.setFileType(FTP.BINARY_FILE_TYPE); FTPFile[] fs = ftpClient.listDirectories(); //输出文件数量 Logger.d(TAG, "fs.size=" + (fs == null ? -1 : fs.length)); for(FTPFile f : fs){ //打印文件名 Logger.d(TAG, f.getName()); } ftpClient.logout(); ftpClient.disconnect(); } catch (IOException e) { e.printStackTrace(); } } }.start(); } }结果FtpClient: ALog > fs.size=4 FtpClient: ALog > message FtpClient: ALog > music FtpClient: ALog > photo FtpClient: ALog > video参考Android FTP Library [closed]android ftp客户端简单实现
平台Ubuntu 16.14 AndroidStudio4.1.1 Gradle 6.1.1 Android Gradle Plugin Version 4.0.0在另一台Ubuntu20.04, 同样的条件下正常!!问题早期代码编译运行都是正常的, 后面, 由于要生成release版本APK, 发现使用google的仓库一直连接不上(timeout)repositories { maven { url 'https://maven.google.com/' name 'Google' } //google() //maven { url 'https://maven.aliyun.com/repository/google' } maven { url 'https://maven.aliyun.com/repository/jcenter' } }LOG:FAILURE: Build failed with an exception. * What went wrong: A problem occurred configuring root project 'AnsonProjects2'. > Could not resolve all artifacts for configuration ':classpath'. > Could not resolve org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.3.72. Required by: project : > com.android.tools.build:gradle:4.0.0 project : > com.android.tools.build:gradle:4.0.0 > com.android.tools.build:builder:4.0.0 project : > com.android.tools.build:gradle:4.0.0 > com.android.tools.build:aaptcompiler:4.0.0 project : > com.android.tools.build:gradle:4.0.0 > com.android.tools.lint:lint-gradle-api:27.0.0 project : > com.android.tools.build:gradle:4.0.0 > com.android.tools.build:gradle-api:4.0.0 project : > com.android.tools.build:gradle:4.0.0 > androidx.databinding:databinding-compiler-common:4.0.0 project : > com.android.tools.build:gradle:4.0.0 > com.android.tools.build:builder:4.0.0 > com.android.tools:sdk-common:27.0.0 project : > com.android.tools.build:gradle:4.0.0 > com.android.tools.build:builder:4.0.0 > com.android.tools:common:27.0.0 project : > com.android.tools.build:gradle:4.0.0 > com.android.tools.build:builder:4.0.0 > com.android.tools.build:manifest-merger:27.0.0 project : > com.android.tools.build:gradle:4.0.0 > com.android.tools.build:builder:4.0.0 > com.android.tools.analytics-library:tracker:27.0.0 project : > com.android.tools.build:gradle:4.0.0 > com.android.tools.build:builder:4.0.0 > com.android.tools:sdklib:27.0.0 > com.android.tools:repository:27.0.0 project : > com.android.tools.build:gradle:4.0.0 > com.android.tools.build:builder:4.0.0 > com.android.tools:sdk-common:27.0.0 > com.android.tools.analytics-library:shared:27.0.0 > Could not resolve org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.3.72. > Could not get resource 'https://maven.google.com/org/jetbrains/kotlin/kotlin-stdlib-jdk8/1.3.72/kotlin-stdlib-jdk8-1.3.72.pom'. > Could not HEAD 'https://maven.google.com/org/jetbrains/kotlin/kotlin-stdlib-jdk8/1.3.72/kotlin-stdlib-jdk8-1.3.72.pom'. > Connect to maven.google.com:443 [maven.google.com/172.217.26.142] failed: connect timed out > Could not resolve com.android.tools.build:transform-api:2.0.0-deprecated-use-gradle-api. Required by: project : > com.android.tools.build:gradle:4.0.0 > Could not resolve com.android.tools.build:transform-api:2.0.0-deprecated-use-gradle-api. > Could not get resource 'https://maven.google.com/com/android/tools/build/transform-api/2.0.0-deprecated-use-gradle-api/transform-api-2.0.0-deprecated-use-gradle-api.pom'. > Could not HEAD 'https://maven.google.com/com/android/tools/build/transform-api/2.0.0-deprecated-use-gradle-api/transform-api-2.0.0-deprecated-use-gradle-api.pom'. > Connect to maven.google.com:443 [maven.google.com/172.217.26.142] failed: connect timed out > Could not resolve org.ow2.asm:asm:7.0. Required by: project : > com.android.tools.build:gradle:4.0.0 project : > com.android.tools.build:gradle:4.0.0 > com.android.tools.build:builder:4.0.0 project : > com.android.tools.build:gradle:4.0.0 > com.android.tools.build:builder:4.0.0 > org.ow2.asm:asm-tree:7.0 > Could not resolve org.ow2.asm:asm:7.0. > Could not get resource 'https://maven.google.com/org/ow2/asm/asm/7.0/asm-7.0.pom'. > Could not HEAD 'https://maven.google.com/org/ow2/asm/asm/7.0/asm-7.0.pom'. > Connect to maven.google.com:443 [maven.google.com/172.217.26.142] failed: connect timed out > Could not resolve org.ow2.asm:asm-analysis:7.0. Required by: project : > com.android.tools.build:gradle:4.0.0 > Could not resolve org.ow2.asm:asm-analysis:7.0. > Could not get resource 'https://maven.google.com/org/ow2/asm/asm-analysis/7.0/asm-analysis-7.0.pom'. > Could not HEAD 'https://maven.google.com/org/ow2/asm/asm-analysis/7.0/asm-analysis-7.0.pom'. > Connect to maven.google.com:443 [maven.google.com/172.217.26.142] failed: connect timed out > Could not resolve org.ow2.asm:asm-commons:7.0. Required by: project : > com.android.tools.build:gradle:4.0.0 project : > com.android.tools.build:gradle:4.0.0 > com.android.tools.build:builder:4.0.0 > Could not resolve org.ow2.asm:asm-commons:7.0. > Could not get resource 'https://maven.google.com/org/ow2/asm/asm-commons/7.0/asm-commons-7.0.pom'. > Could not HEAD 'https://maven.google.com/org/ow2/asm/asm-commons/7.0/asm-commons-7.0.pom'. > Connect to maven.google.com:443 [maven.google.com/172.217.26.142] failed: connect timed out > Could not resolve org.ow2.asm:asm-util:7.0. Required by: project : > com.android.tools.build:gradle:4.0.0 project : > com.android.tools.build:gradle:4.0.0 > com.android.tools.build:builder:4.0.0 > Could not resolve org.ow2.asm:asm-util:7.0. > Could not get resource 'https://maven.google.com/org/ow2/asm/asm-util/7.0/asm-util-7.0.pom'. > Could not HEAD 'https://maven.google.com/org/ow2/asm/asm-util/7.0/asm-util-7.0.pom'. > Connect to maven.google.com:443 [maven.google.com/172.217.26.142] failed: connect timed out > Could not resolve net.sf.jopt-simple:jopt-simple:4.9. Required by: project : > com.android.tools.build:gradle:4.0.0 project : > com.android.tools.build:gradle:4.0.0 > com.android.tools.build:builder:4.0.0 > Could not resolve net.sf.jopt-simple:jopt-simple:4.9. > Could not get resource 'https://maven.google.com/net/sf/jopt-simple/jopt-simple/4.9/jopt-simple-4.9.pom'. > Could not HEAD 'https://maven.google.com/net/sf/jopt-simple/jopt-simple/4.9/jopt-simple-4.9.pom'. > Connect to maven.google.com:443 [maven.google.com/172.217.26.142] failed: connect timed out > Could not resolve net.sf.proguard:proguard-gradle:6.0.3. Required by: project : > com.android.tools.build:gradle:4.0.0 > Could not resolve net.sf.proguard:proguard-gradle:6.0.3. > Could not get resource 'https://maven.google.com/net/sf/proguard/proguard-gradle/6.0.3/proguard-gradle-6.0.3.pom'. > Could not HEAD 'https://maven.google.com/net/sf/proguard/proguard-gradle/6.0.3/proguard-gradle-6.0.3.pom'. > Connect to maven.google.com:443 [maven.google.com/172.217.26.142] failed: connect timed out > Could not resolve org.ow2.asm:asm:7.0. Required by: project : > com.android.tools.build:gradle:4.0.0 > com.android.tools.build.jetifier:jetifier-processor:1.0.0-beta09 > Could not resolve org.ow2.asm:asm:7.0. > Could not get resource 'https://maven.google.com/org/ow2/asm/asm/7.0/asm-7.0.pom'. > Could not HEAD 'https://maven.google.com/org/ow2/asm/asm/7.0/asm-7.0.pom'. > Connect to maven.google.com:443 [maven.google.com/172.217.26.142] failed: connect timed out > Could not resolve org.ow2.asm:asm-util:7.0. Required by: project : > com.android.tools.build:gradle:4.0.0 > com.android.tools.build.jetifier:jetifier-processor:1.0.0-beta09 > Could not resolve org.ow2.asm:asm-util:7.0. > Could not get resource 'https://maven.google.com/org/ow2/asm/asm-util/7.0/asm-util-7.0.pom'. > Could not HEAD 'https://maven.google.com/org/ow2/asm/asm-util/7.0/asm-util-7.0.pom'. > Connect to maven.google.com:443 [maven.google.com/172.217.26.142] failed: connect timed out > Could not resolve org.ow2.asm:asm-commons:7.0. Required by: project : > com.android.tools.build:gradle:4.0.0 > com.android.tools.build.jetifier:jetifier-processor:1.0.0-beta09 > Could not resolve org.ow2.asm:asm-commons:7.0. > Could not get resource 'https://maven.google.com/org/ow2/asm/asm-commons/7.0/asm-commons-7.0.pom'. > Could not HEAD 'https://maven.google.com/org/ow2/asm/asm-commons/7.0/asm-commons-7.0.pom'. > Connect to maven.google.com:443 [maven.google.com/172.217.26.142] failed: connect timed out * Try: Run with --info or --debug option to get more log output. Run with --scan to get full insights. * Exception is: org.gradle.api.ProjectConfigurationException: A problem occurred configuring root project 'AnsonProjects2'. at org.gradle.configuration.project.LifecycleProjectEvaluator.wrapException(LifecycleProjectEvaluator.java:80) at org.gradle.configuration.project.LifecycleProjectEvaluator.addConfigurationFailure(LifecycleProjectEvaluator.java:73) at org.gradle.configuration.project.LifecycleProjectEvaluator.access$600(LifecycleProjectEvaluator.java:53) at org.gradle.configuration.project.LifecycleProjectEvaluator$EvaluateProject$1.run(LifecycleProjectEvaluator.java:109) at org.gradle.internal.Factories$1.create(Factories.java:26) at org.gradle.internal.work.DefaultWorkerLeaseService.withLocks(DefaultWorkerLeaseService.java:189) at org.gradle.internal.work.StopShieldingWorkerLeaseService.withLocks(StopShieldingWorkerLeaseService.java:40) at org.gradle.api.internal.project.DefaultProjectStateRegistry$ProjectStateImpl.withProjectLock(DefaultProjectStateRegistry.java:238) at org.gradle.api.internal.project.DefaultProjectStateRegistry$ProjectStateImpl.withMutableState(DefaultProjectStateRegistry.java:232) at org.gradle.api.internal.project.DefaultProjectStateRegistry$ProjectStateImpl.withMutableState(DefaultProjectStateRegistry.java:193) at org.gradle.configuration.project.LifecycleProjectEvaluator$EvaluateProject.run(LifecycleProjectEvaluator.java:96) at org.gradle.internal.operations.DefaultBuildOperationExecutor$RunnableBuildOperationWorker.execute(DefaultBuildOperationExecutor.java:402) at org.gradle.internal.operations.DefaultBuildOperationExecutor$RunnableBuildOperationWorker.execute(DefaultBuildOperationExecutor.java:394) at org.gradle.internal.operations.DefaultBuildOperationExecutor$1.execute(DefaultBuildOperationExecutor.java:165) at org.gradle.internal.operations.DefaultBuildOperationExecutor.execute(DefaultBuildOperationExecutor.java:250) at org.gradle.internal.operations.DefaultBuildOperationExecutor.execute(DefaultBuildOperationExecutor.java:158) at org.gradle.internal.operations.DefaultBuildOperationExecutor.run(DefaultBuildOperationExecutor.java:92) at org.gradle.internal.operations.DelegatingBuildOperationExecutor.run(DelegatingBuildOperationExecutor.java:31) at org.gradle.configuration.project.LifecycleProjectEvaluator.evaluate(LifecycleProjectEvaluator.java:68) at org.gradle.api.internal.project.DefaultProject.evaluate(DefaultProject.java:699) at org.gradle.api.internal.project.DefaultProject.evaluate(DefaultProject.java:142) at org.gradle.execution.TaskPathProjectEvaluator.configure(TaskPathProjectEvaluator.java:36) at org.gradle.execution.TaskPathProjectEvaluator.configureHierarchy(TaskPathProjectEvaluator.java:62) at org.gradle.configuration.DefaultProjectsPreparer.prepareProjects(DefaultProjectsPreparer.java:61) at org.gradle.configuration.BuildOperatingFiringProjectsPreparer$ConfigureBuild.run(BuildOperatingFiringProjectsPreparer.java:52) at org.gradle.internal.operations.DefaultBuildOperationExecutor$RunnableBuildOperationWorker.execute(DefaultBuildOperationExecutor.java:402) at org.gradle.internal.operations.DefaultBuildOperationExecutor$RunnableBuildOperationWorker.execute(DefaultBuildOperationExecutor.java:394) at org.gradle.internal.operations.DefaultBuildOperationExecutor$1.execute(DefaultBuildOperationExecutor.java:165) at org.gradle.internal.operations.DefaultBuildOperationExecutor.execute(DefaultBuildOperationExecutor.java:250) at org.gradle.internal.operations.DefaultBuildOperationExecutor.execute(DefaultBuildOperationExecutor.java:158) at org.gradle.internal.operations.DefaultBuildOperationExecutor.run(DefaultBuildOperationExecutor.java:92) at org.gradle.internal.operations.DelegatingBuildOperationExecutor.run(DelegatingBuildOperationExecutor.java:31) at org.gradle.configuration.BuildOperatingFiringProjectsPreparer.prepareProjects(BuildOperatingFiringProjectsPreparer.java:40) at org.gradle.initialization.DefaultGradleLauncher.prepareProjects(DefaultGradleLauncher.java:207) at org.gradle.initialization.DefaultGradleLauncher.doClassicBuildStages(DefaultGradleLauncher.java:145) at org.gradle.initialization.DefaultGradleLauncher.doBuildStages(DefaultGradleLauncher.java:130) at org.gradle.initialization.DefaultGradleLauncher.executeTasks(DefaultGradleLauncher.java:110) at org.gradle.internal.invocation.GradleBuildController$1.execute(GradleBuildController.java:60) at org.gradle.internal.invocation.GradleBuildController$1.execute(GradleBuildController.java:57) at org.gradle.internal.invocation.GradleBuildController$3.create(GradleBuildController.java:85) at org.gradle.internal.invocation.GradleBuildController$3.create(GradleBuildController.java:78) at org.gradle.internal.work.DefaultWorkerLeaseService.withLocks(DefaultWorkerLeaseService.java:189) at org.gradle.internal.work.StopShieldingWorkerLeaseService.withLocks(StopShieldingWorkerLeaseService.java:40) at org.gradle.internal.invocation.GradleBuildController.doBuild(GradleBuildController.java:78) at org.gradle.internal.invocation.GradleBuildController.run(GradleBuildController.java:57) at org.gradle.tooling.internal.provider.runner.ClientProvidedPhasedActionRunner.run(ClientProvidedPhasedActionRunner.java:60) at org.gradle.launcher.exec.ChainingBuildActionRunner.run(ChainingBuildActionRunner.java:35) at org.gradle.launcher.exec.ChainingBuildActionRunner.run(ChainingBuildActionRunner.java:35) at org.gradle.launcher.exec.BuildOutcomeReportingBuildActionRunner.run(BuildOutcomeReportingBuildActionRunner.java:63) at org.gradle.tooling.internal.provider.ValidatingBuildActionRunner.run(ValidatingBuildActionRunner.java:32) at org.gradle.launcher.exec.BuildCompletionNotifyingBuildActionRunner.run(BuildCompletionNotifyingBuildActionRunner.java:39) at org.gradle.launcher.exec.RunAsBuildOperationBuildActionRunner$3.call(RunAsBuildOperationBuildActionRunner.java:51) at org.gradle.launcher.exec.RunAsBuildOperationBuildActionRunner$3.call(RunAsBuildOperationBuildActionRunner.java:45) at org.gradle.internal.operations.DefaultBuildOperationExecutor$CallableBuildOperationWorker.execute(DefaultBuildOperationExecutor.java:416) at org.gradle.internal.operations.DefaultBuildOperationExecutor$CallableBuildOperationWorker.execute(DefaultBuildOperationExecutor.java:406) at org.gradle.internal.operations.DefaultBuildOperationExecutor$1.execute(DefaultBuildOperationExecutor.java:165) at org.gradle.internal.operations.DefaultBuildOperationExecutor.execute(DefaultBuildOperationExecutor.java:250) at org.gradle.internal.operations.DefaultBuildOperationExecutor.execute(DefaultBuildOperationExecutor.java:158) at org.gradle.internal.operations.DefaultBuildOperationExecutor.call(DefaultBuildOperationExecutor.java:102) at org.gradle.internal.operations.DelegatingBuildOperationExecutor.call(DelegatingBuildOperationExecutor.java:36) at org.gradle.launcher.exec.RunAsBuildOperationBuildActionRunner.run(RunAsBuildOperationBuildActionRunner.java:45) at org.gradle.launcher.exec.InProcessBuildActionExecuter$1.transform(InProcessBuildActionExecuter.java:50) at org.gradle.launcher.exec.InProcessBuildActionExecuter$1.transform(InProcessBuildActionExecuter.java:47) at org.gradle.composite.internal.DefaultRootBuildState.run(DefaultRootBuildState.java:80) at org.gradle.launcher.exec.InProcessBuildActionExecuter.execute(InProcessBuildActionExecuter.java:47) at org.gradle.launcher.exec.InProcessBuildActionExecuter.execute(InProcessBuildActionExecuter.java:31) at org.gradle.launcher.exec.BuildTreeScopeBuildActionExecuter.execute(BuildTreeScopeBuildActionExecuter.java:42) at org.gradle.launcher.exec.BuildTreeScopeBuildActionExecuter.execute(BuildTreeScopeBuildActionExecuter.java:28) at org.gradle.tooling.internal.provider.ContinuousBuildActionExecuter.execute(ContinuousBuildActionExecuter.java:78) at org.gradle.tooling.internal.provider.ContinuousBuildActionExecuter.execute(ContinuousBuildActionExecuter.java:52) at org.gradle.tooling.internal.provider.SubscribableBuildActionExecuter.execute(SubscribableBuildActionExecuter.java:60) at org.gradle.tooling.internal.provider.SubscribableBuildActionExecuter.execute(SubscribableBuildActionExecuter.java:38) at org.gradle.tooling.internal.provider.SessionScopeBuildActionExecuter.execute(SessionScopeBuildActionExecuter.java:68) at org.gradle.tooling.internal.provider.SessionScopeBuildActionExecuter.execute(SessionScopeBuildActionExecuter.java:38) at org.gradle.tooling.internal.provider.GradleThreadBuildActionExecuter.execute(GradleThreadBuildActionExecuter.java:37) at org.gradle.tooling.internal.provider.GradleThreadBuildActionExecuter.execute(GradleThreadBuildActionExecuter.java:26) at org.gradle.tooling.internal.provider.ParallelismConfigurationBuildActionExecuter.execute(ParallelismConfigurationBuildActionExecuter.java:43) at org.gradle.tooling.internal.provider.ParallelismConfigurationBuildActionExecuter.execute(ParallelismConfigurationBuildActionExecuter.java:29) at org.gradle.tooling.internal.provider.StartParamsValidatingActionExecuter.execute(StartParamsValidatingActionExecuter.java:60) at org.gradle.tooling.internal.provider.StartParamsValidatingActionExecuter.execute(StartParamsValidatingActionExecuter.java:32) at org.gradle.tooling.internal.provider.SessionFailureReportingActionExecuter.execute(SessionFailureReportingActionExecuter.java:55) at org.gradle.tooling.internal.provider.SessionFailureReportingActionExecuter.execute(SessionFailureReportingActionExecuter.java:41) at org.gradle.tooling.internal.provider.SetupLoggingActionExecuter.execute(SetupLoggingActionExecuter.java:48) at org.gradle.tooling.internal.provider.SetupLoggingActionExecuter.execute(SetupLoggingActionExecuter.java:32) at org.gradle.launcher.daemon.server.exec.ExecuteBuild.doBuild(ExecuteBuild.java:68) at org.gradle.launcher.daemon.server.exec.BuildCommandOnly.execute(BuildCommandOnly.java:37) at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:104) at org.gradle.launcher.daemon.server.exec.WatchForDisconnection.execute(WatchForDisconnection.java:39) at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:104) at org.gradle.launcher.daemon.server.exec.ResetDeprecationLogger.execute(ResetDeprecationLogger.java:27) at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:104) at org.gradle.launcher.daemon.server.exec.RequestStopIfSingleUsedDaemon.execute(RequestStopIfSingleUsedDaemon.java:35) at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:104) at org.gradle.launcher.daemon.server.exec.ForwardClientInput$2.create(ForwardClientInput.java:78) at org.gradle.launcher.daemon.server.exec.ForwardClientInput$2.create(ForwardClientInput.java:75) at org.gradle.util.Swapper.swap(Swapper.java:38) at org.gradle.launcher.daemon.server.exec.ForwardClientInput.execute(ForwardClientInput.java:75) at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:104) at org.gradle.launcher.daemon.server.exec.LogAndCheckHealth.execute(LogAndCheckHealth.java:55) at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:104) at org.gradle.launcher.daemon.server.exec.LogToClient.doBuild(LogToClient.java:63) at org.gradle.launcher.daemon.server.exec.BuildCommandOnly.execute(BuildCommandOnly.java:37) at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:104) at org.gradle.launcher.daemon.server.exec.EstablishBuildEnvironment.doBuild(EstablishBuildEnvironment.java:82) at org.gradle.launcher.daemon.server.exec.BuildCommandOnly.execute(BuildCommandOnly.java:37) at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:104) at org.gradle.launcher.daemon.server.exec.StartBuildOrRespondWithBusy$1.run(StartBuildOrRespondWithBusy.java:52) at org.gradle.launcher.daemon.server.DaemonStateCoordinator$1.run(DaemonStateCoordinator.java:297) at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:64) at org.gradle.internal.concurrent.ManagedExecutorImpl$1.run(ManagedExecutorImpl.java:48) at org.gradle.internal.concurrent.ThreadFactoryImpl$ManagedThreadRunnable.run(ThreadFactoryImpl.java:56) Caused by: org.gradle.api.internal.artifacts.ivyservice.DefaultLenientConfiguration$ArtifactResolveException: Could not resolve all artifacts for configuration ':classpath'. at org.gradle.api.internal.artifacts.configurations.DefaultConfiguration.rethrowFailure(DefaultConfiguration.java:1293) at org.gradle.api.internal.artifacts.configurations.DefaultConfiguration.access$2300(DefaultConfiguration.java:140) at org.gradle.api.internal.artifacts.configurations.DefaultConfiguration$ConfigurationArtifactCollection.ensureResolved(DefaultConfiguration.java:1780) at org.gradle.api.internal.artifacts.configurations.DefaultConfiguration$ConfigurationArtifactCollection.getArtifacts(DefaultConfiguration.java:1752) at org.gradle.composite.internal.CompositeBuildClassPathInitializer.execute(CompositeBuildClassPathInitializer.java:45) at org.gradle.composite.internal.CompositeBuildClassPathInitializer.execute(CompositeBuildClassPathInitializer.java:32) at org.gradle.api.internal.initialization.DefaultScriptClassPathResolver.resolveClassPath(DefaultScriptClassPathResolver.java:37) at org.gradle.api.internal.initialization.DefaultScriptHandler.getScriptClassPath(DefaultScriptHandler.java:87) at org.gradle.plugin.use.internal.DefaultPluginRequestApplicator.defineScriptHandlerClassScope(DefaultPluginRequestApplicator.java:210) at org.gradle.plugin.use.internal.DefaultPluginRequestApplicator.applyPlugins(DefaultPluginRequestApplicator.java:83) at org.gradle.configuration.DefaultScriptPluginFactory$ScriptPluginImpl.apply(DefaultScriptPluginFactory.java:216) at org.gradle.configuration.BuildOperationScriptPlugin$1$1.run(BuildOperationScriptPlugin.java:69) at org.gradle.internal.operations.DefaultBuildOperationExecutor$RunnableBuildOperationWorker.execute(DefaultBuildOperationExecutor.java:402) at org.gradle.internal.operations.DefaultBuildOperationExecutor$RunnableBuildOperationWorker.execute(DefaultBuildOperationExecutor.java:394) at org.gradle.internal.operations.DefaultBuildOperationExecutor$1.execute(DefaultBuildOperationExecutor.java:165) at org.gradle.internal.operations.DefaultBuildOperationExecutor.execute(DefaultBuildOperationExecutor.java:250) at org.gradle.internal.operations.DefaultBuildOperationExecutor.execute(DefaultBuildOperationExecutor.java:158) at org.gradle.internal.operations.DefaultBuildOperationExecutor.run(DefaultBuildOperationExecutor.java:92) at org.gradle.internal.operations.DelegatingBuildOperationExecutor.run(DelegatingBuildOperationExecutor.java:31) at org.gradle.configuration.BuildOperationScriptPlugin$1.execute(BuildOperationScriptPlugin.java:66) at org.gradle.configuration.BuildOperationScriptPlugin$1.execute(BuildOperationScriptPlugin.java:63) at org.gradle.configuration.internal.DefaultUserCodeApplicationContext.apply(DefaultUserCodeApplicationContext.java:49) at org.gradle.configuration.BuildOperationScriptPlugin.apply(BuildOperationScriptPlugin.java:63) at org.gradle.configuration.project.BuildScriptProcessor$1.run(BuildScriptProcessor.java:45) at org.gradle.internal.Factories$1.create(Factories.java:26) at org.gradle.api.internal.project.DefaultProjectStateRegistry$ProjectStateImpl.withMutableState(DefaultProjectStateRegistry.java:212) at org.gradle.api.internal.project.DefaultProjectStateRegistry$ProjectStateImpl.withMutableState(DefaultProjectStateRegistry.java:193) at org.gradle.configuration.project.BuildScriptProcessor.execute(BuildScriptProcessor.java:42) at org.gradle.configuration.project.BuildScriptProcessor.execute(BuildScriptProcessor.java:26) at org.gradle.configuration.project.ConfigureActionsProjectEvaluator.evaluate(ConfigureActionsProjectEvaluator.java:35) at org.gradle.configuration.project.LifecycleProjectEvaluator$EvaluateProject$1.run(LifecycleProjectEvaluator.java:107) ... 107 more Caused by: org.gradle.internal.resolve.ModuleVersionResolveException: Could not resolve org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.3.72. Required by: project : > com.android.tools.build:gradle:4.0.0 project : > com.android.tools.build:gradle:4.0.0 > com.android.tools.build:builder:4.0.0 project : > com.android.tools.build:gradle:4.0.0 > com.android.tools.build:aaptcompiler:4.0.0 project : > com.android.tools.build:gradle:4.0.0 > com.android.tools.lint:lint-gradle-api:27.0.0 project : > com.android.tools.build:gradle:4.0.0 > com.android.tools.build:gradle-api:4.0.0 project : > com.android.tools.build:gradle:4.0.0 > androidx.databinding:databinding-compiler-common:4.0.0 project : > com.android.tools.build:gradle:4.0.0 > com.android.tools.build:builder:4.0.0 > com.android.tools:sdk-common:27.0.0 project : > com.android.tools.build:gradle:4.0.0 > com.android.tools.build:builder:4.0.0 > com.android.tools:common:27.0.0 project : > com.android.tools.build:gradle:4.0.0 > com.android.tools.build:builder:4.0.0 > com.android.tools.build:manifest-merger:27.0.0 project : > com.android.tools.build:gradle:4.0.0 > com.android.tools.build:builder:4.0.0 > com.android.tools.analytics-library:tracker:27.0.0 project : > com.android.tools.build:gradle:4.0.0 > com.android.tools.build:builder:4.0.0 > com.android.tools:sdklib:27.0.0 > com.android.tools:repository:27.0.0 project : > com.android.tools.build:gradle:4.0.0 > com.android.tools.build:builder:4.0.0 > com.android.tools:sdk-common:27.0.0 > com.android.tools.analytics-library:shared:27.0.0 Caused by: org.gradle.internal.resolve.ModuleVersionResolveException: Could not resolve org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.3.72. Caused by: org.gradle.api.resources.ResourceException: Could not get resource 'https://maven.google.com/org/jetbrains/kotlin/kotlin-stdlib-jdk8/1.3.72/kotlin-stdlib-jdk8-1.3.72.pom'. at org.gradle.internal.resource.ResourceExceptions.failure(ResourceExceptions.java:74) at org.gradle.internal.resource.ResourceExceptions.getFailed(ResourceExceptions.java:57) at org.gradle.api.internal.artifacts.repositories.resolver.DefaultExternalResourceArtifactResolver.downloadByCoords(DefaultExternalResourceArtifactResolver.java:144) at org.gradle.api.internal.artifacts.repositories.resolver.DefaultExternalResourceArtifactResolver.downloadStaticResource(DefaultExternalResourceArtifactResolver.java:94) at org.gradle.api.internal.artifacts.repositories.resolver.DefaultExternalResourceArtifactResolver.resolveArtifact(DefaultExternalResourceArtifactResolver.java:60) at org.gradle.api.internal.artifacts.repositories.metadata.AbstractRepositoryMetadataSource.parseMetaDataFromArtifact(AbstractRepositoryMetadataSource.java:78) at org.gradle.api.internal.artifacts.repositories.metadata.AbstractRepositoryMetadataSource.create(AbstractRepositoryMetadataSource.java:68) at org.gradle.api.internal.artifacts.repositories.metadata.DefaultMavenPomMetadataSource.create(DefaultMavenPomMetadataSource.java:40) at org.gradle.api.internal.artifacts.repositories.metadata.RedirectingGradleMetadataModuleMetadataSource.create(RedirectingGradleMetadataModuleMetadataSource.java:51) at org.gradle.api.internal.artifacts.repositories.resolver.ExternalResourceResolver.resolveStaticDependency(ExternalResourceResolver.java:252) at org.gradle.api.internal.artifacts.repositories.resolver.MavenResolver.doResolveComponentMetaData(MavenResolver.java:130) at org.gradle.api.internal.artifacts.repositories.resolver.ExternalResourceResolver$RemoteRepositoryAccess.resolveComponentMetaData(ExternalResourceResolver.java:479) at org.gradle.api.internal.artifacts.ivyservice.ivyresolve.CachingModuleComponentRepository$ResolveAndCacheRepositoryAccess.resolveComponentMetaData(CachingModuleComponentRepository.java:379) at org.gradle.api.internal.artifacts.ivyservice.ivyresolve.ErrorHandlingModuleComponentRepository$ErrorHandlingModuleComponentRepositoryAccess.lambda$resolveComponentMetaData$5(ErrorHandlingModuleComponentRepository.java:154) at org.gradle.api.internal.artifacts.ivyservice.ivyresolve.ErrorHandlingModuleComponentRepository$ErrorHandlingModuleComponentRepositoryAccess.lambda$tryResolveAndMaybeBlacklist$18(ErrorHandlingModuleComponentRepository.java:223) at org.gradle.api.internal.artifacts.ivyservice.ivyresolve.ErrorHandlingModuleComponentRepository$ErrorHandlingModuleComponentRepositoryAccess.tryResolveAndMaybeBlacklist(ErrorHandlingModuleComponentRepository.java:237) at org.gradle.api.internal.artifacts.ivyservice.ivyresolve.ErrorHandlingModuleComponentRepository$ErrorHandlingModuleComponentRepositoryAccess.tryResolveAndMaybeBlacklist(ErrorHandlingModuleComponentRepository.java:222) at org.gradle.api.internal.artifacts.ivyservice.ivyresolve.ErrorHandlingModuleComponentRepository$ErrorHandlingModuleComponentRepositoryAccess.performOperationWithRetries(ErrorHandlingModuleComponentRepository.java:215) at org.gradle.api.internal.artifacts.ivyservice.ivyresolve.ErrorHandlingModuleComponentRepository$ErrorHandlingModuleComponentRepositoryAccess.resolveComponentMetaData(ErrorHandlingModuleComponentRepository.java:153) at org.gradle.api.internal.artifacts.ivyservice.ivyresolve.ComponentMetaDataResolveState.process(ComponentMetaDataResolveState.java:69) at org.gradle.api.internal.artifacts.ivyservice.ivyresolve.ComponentMetaDataResolveState.resolve(ComponentMetaDataResolveState.java:61) at org.gradle.api.internal.artifacts.ivyservice.ivyresolve.RepositoryChainComponentMetaDataResolver.findBestMatch(RepositoryChainComponentMetaDataResolver.java:139) at org.gradle.api.internal.artifacts.ivyservice.ivyresolve.RepositoryChainComponentMetaDataResolver.findBestMatch(RepositoryChainComponentMetaDataResolver.java:120) at org.gradle.api.internal.artifacts.ivyservice.ivyresolve.RepositoryChainComponentMetaDataResolver.resolveModule(RepositoryChainComponentMetaDataResolver.java:93) at org.gradle.api.internal.artifacts.ivyservice.ivyresolve.RepositoryChainComponentMetaDataResolver.resolve(RepositoryChainComponentMetaDataResolver.java:64) at org.gradle.api.internal.artifacts.ivyservice.resolveengine.ComponentResolversChain$ComponentMetaDataResolverChain.resolve(ComponentResolversChain.java:95) at org.gradle.api.internal.artifacts.ivyservice.clientmodule.ClientModuleResolver.resolve(ClientModuleResolver.java:65) at org.gradle.api.internal.artifacts.ivyservice.resolveengine.graph.builder.ComponentState.resolve(ComponentState.java:195) at org.gradle.api.internal.artifacts.ivyservice.resolveengine.graph.builder.ComponentState.getMetadata(ComponentState.java:142) at org.gradle.api.internal.artifacts.ivyservice.resolveengine.graph.builder.DownloadMetadataOperation.run(DownloadMetadataOperation.java:31) at org.gradle.internal.operations.DefaultBuildOperationExecutor$RunnableBuildOperationWorker.execute(DefaultBuildOperationExecutor.java:402) at org.gradle.internal.operations.DefaultBuildOperationExecutor$RunnableBuildOperationWorker.execute(DefaultBuildOperationExecutor.java:394) at org.gradle.internal.operations.DefaultBuildOperationExecutor$1.execute(DefaultBuildOperationExecutor.java:165) at org.gradle.internal.operations.DefaultBuildOperationExecutor.execute(DefaultBuildOperationExecutor.java:250) at org.gradle.internal.operations.DefaultBuildOperationExecutor.execute(DefaultBuildOperationExecutor.java:158) at org.gradle.internal.operations.DefaultBuildOperationExecutor.access$1500(DefaultBuildOperationExecutor.java:49) at org.gradle.internal.operations.DefaultBuildOperationExecutor$ParentPreservingQueueWorker.execute(DefaultBuildOperationExecutor.java:444) at org.gradle.internal.operations.DefaultBuildOperationQueue$WorkerRunnable.runOperation(DefaultBuildOperationQueue.java:231) at org.gradle.internal.operations.DefaultBuildOperationQueue$WorkerRunnable.access$600(DefaultBuildOperationQueue.java:173) at org.gradle.internal.operations.DefaultBuildOperationQueue$WorkerRunnable$1.create(DefaultBuildOperationQueue.java:210) at org.gradle.internal.operations.DefaultBuildOperationQueue$WorkerRunnable$1.create(DefaultBuildOperationQueue.java:204) at org.gradle.internal.work.DefaultWorkerLeaseService.withLocks(DefaultWorkerLeaseService.java:189) at org.gradle.internal.operations.DefaultBuildOperationQueue$WorkerRunnable.runBatch(DefaultBuildOperationQueue.java:204) at org.gradle.internal.operations.DefaultBuildOperationQueue$WorkerRunnable.run(DefaultBuildOperationQueue.java:178) at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:64) at org.gradle.internal.concurrent.ManagedExecutorImpl$1.run(ManagedExecutorImpl.java:48) at org.gradle.internal.concurrent.ThreadFactoryImpl$ManagedThreadRunnable.run(ThreadFactoryImpl.java:56) Caused by: org.gradle.internal.resource.transport.http.HttpRequestException: Could not HEAD 'https://maven.google.com/org/jetbrains/kotlin/kotlin-stdlib-jdk8/1.3.72/kotlin-stdlib-jdk8-1.3.72.pom'. at org.gradle.internal.resource.transport.http.HttpClientHelper.performRequest(HttpClientHelper.java:101) at org.gradle.internal.resource.transport.http.HttpClientHelper.performRawHead(HttpClientHelper.java:76) at org.gradle.internal.resource.transport.http.HttpClientHelper.performHead(HttpClientHelper.java:80) at org.gradle.internal.resource.transport.http.HttpResourceAccessor.getMetaData(HttpResourceAccessor.java:66) at org.gradle.internal.resource.transfer.DefaultExternalResourceConnector.getMetaData(DefaultExternalResourceConnector.java:63) at org.gradle.internal.resource.transfer.AccessorBackedExternalResource.getMetaData(AccessorBackedExternalResource.java:201) at org.gradle.internal.resource.BuildOperationFiringExternalResourceDecorator$1.call(BuildOperationFiringExternalResourceDecorator.java:61) at org.gradle.internal.resource.BuildOperationFiringExternalResourceDecorator$1.call(BuildOperationFiringExternalResourceDecorator.java:58) at org.gradle.internal.operations.DefaultBuildOperationExecutor$CallableBuildOperationWorker.execute(DefaultBuildOperationExecutor.java:416) at org.gradle.internal.operations.DefaultBuildOperationExecutor$CallableBuildOperationWorker.execute(DefaultBuildOperationExecutor.java:406) at org.gradle.internal.operations.DefaultBuildOperationExecutor$1.execute(DefaultBuildOperationExecutor.java:165) at org.gradle.internal.operations.DefaultBuildOperationExecutor.execute(DefaultBuildOperationExecutor.java:250) at org.gradle.internal.operations.DefaultBuildOperationExecutor.execute(DefaultBuildOperationExecutor.java:158) at org.gradle.internal.operations.DefaultBuildOperationExecutor.call(DefaultBuildOperationExecutor.java:102) at org.gradle.internal.operations.DelegatingBuildOperationExecutor.call(DelegatingBuildOperationExecutor.java:36) at org.gradle.internal.resource.BuildOperationFiringExternalResourceDecorator.getMetaData(BuildOperationFiringExternalResourceDecorator.java:58) at org.gradle.internal.resource.transfer.DefaultCacheAwareExternalResourceAccessor$1.get(DefaultCacheAwareExternalResourceAccessor.java:105) at org.gradle.internal.resource.transfer.DefaultCacheAwareExternalResourceAccessor$1.get(DefaultCacheAwareExternalResourceAccessor.java:85) at org.gradle.cache.internal.ProducerGuard$AdaptiveProducerGuard.guardByKey(ProducerGuard.java:97) at org.gradle.internal.resource.transfer.DefaultCacheAwareExternalResourceAccessor.getResource(DefaultCacheAwareExternalResourceAccessor.java:85) at org.gradle.api.internal.artifacts.repositories.resolver.DefaultExternalResourceArtifactResolver.downloadByCoords(DefaultExternalResourceArtifactResolver.java:139) ... 44 more Caused by: org.apache.http.conn.ConnectTimeoutException: Connect to maven.google.com:443 [maven.google.com/172.217.26.142] failed: connect timed out at org.apache.http.impl.conn.DefaultHttpClientConnectionOperator.connect(DefaultHttpClientConnectionOperator.java:151) at org.apache.http.impl.conn.PoolingHttpClientConnectionManager.connect(PoolingHttpClientConnectionManager.java:374) at org.apache.http.impl.execchain.MainClientExec.establishRoute(MainClientExec.java:393) at org.apache.http.impl.execchain.MainClientExec.execute(MainClientExec.java:236) at org.apache.http.impl.execchain.ProtocolExec.execute(ProtocolExec.java:186) at org.apache.http.impl.execchain.RetryExec.execute(RetryExec.java:89) at org.apache.http.impl.execchain.RedirectExec.execute(RedirectExec.java:110) at org.apache.http.impl.client.InternalHttpClient.doExecute(InternalHttpClient.java:185) at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:83) at org.gradle.internal.resource.transport.http.HttpClientHelper.performHttpRequest(HttpClientHelper.java:141) at org.gradle.internal.resource.transport.http.HttpClientHelper.performHttpRequest(HttpClientHelper.java:117) at org.gradle.internal.resource.transport.http.HttpClientHelper.executeGetOrHead(HttpClientHelper.java:106) at org.gradle.internal.resource.transport.http.HttpClientHelper.performRequest(HttpClientHelper.java:97) ... 64 more Caused by: java.net.SocketTimeoutException: connect timed out at org.apache.http.conn.ssl.SSLConnectionSocketFactory.connectSocket(SSLConnectionSocketFactory.java:368) at org.apache.http.impl.conn.DefaultHttpClientConnectionOperator.connect(DefaultHttpClientConnectionOperator.java:142) ... 76 more * Get more help at https://help.gradle.org BUILD FAILED in 1m 33s于是尝试使用阿里的镜像仓库, 然后在编译同步代码时, 提示前言中不允许有内容// Top-level build file where you can add configuration options common to all sub-projects/modules. buildscript { repositories { //google() maven { url 'https://maven.aliyun.com/repository/google' } maven { url 'https://maven.aliyun.com/repository/jcenter' } } dependencies { classpath 'com.android.tools.build:gradle:4.0.0' // NOTE: Do not place your application dependencies here; they belong // in the individual module build.gradle files } } allprojects { repositories { //google() maven { url 'https://maven.aliyun.com/repository/google' } maven { url 'https://maven.aliyun.com/repository/jcenter' } } } task clean(type: Delete) { delete rootProject.buildDir }LOG:> Configure project : [Fatal Error] lint-gradle-api-27.0.0.pom:1:44: 前言中不允许有内容。 [Fatal Error] builder-4.0.0.pom:1:44: 前言中不允许有内容。 [Fatal Error] builder-test-api-4.0.0.pom:1:44: 前言中不允许有内容。 FAILURE: Build failed with an exception. * What went wrong: A problem occurred configuring root project 'AnsonProjects2'. > Could not resolve all artifacts for configuration ':classpath'. > Could not resolve com.android.tools.build:builder:4.0.0. Required by: project : > com.android.tools.build:gradle:4.0.0 > Could not resolve com.android.tools.build:builder:4.0.0. > Could not parse POM https://maven.aliyun.com/repository/google/com/android/tools/build/builder/4.0.0/builder-4.0.0.pom > 前言中不允许有内容。 > Could not resolve com.android.tools.lint:lint-gradle-api:27.0.0. Required by: project : > com.android.tools.build:gradle:4.0.0 > Could not resolve com.android.tools.lint:lint-gradle-api:27.0.0. > Could not parse POM https://maven.aliyun.com/repository/google/com/android/tools/lint/lint-gradle-api/27.0.0/lint-gradle-api-27.0.0.pom > 前言中不允许有内容。 > Could not resolve com.android.tools.build:builder-test-api:4.0.0. Required by: project : > com.android.tools.build:gradle:4.0.0 > com.android.tools.build:gradle-api:4.0.0 > Could not resolve com.android.tools.build:builder-test-api:4.0.0. > Could not parse POM https://maven.aliyun.com/repository/google/com/android/tools/build/builder-test-api/4.0.0/builder-test-api-4.0.0.pom > 前言中不允许有内容。 * Try: Run with --info or --debug option to get more log output. Run with --scan to get full insights. * Exception is: org.gradle.api.ProjectConfigurationException: A problem occurred configuring root project 'AnsonProjects2'. at org.gradle.configuration.project.LifecycleProjectEvaluator.wrapException(LifecycleProjectEvaluator.java:80) at org.gradle.configuration.project.LifecycleProjectEvaluator.addConfigurationFailure(LifecycleProjectEvaluator.java:73) at org.gradle.configuration.project.LifecycleProjectEvaluator.access$600(LifecycleProjectEvaluator.java:53) at org.gradle.configuration.project.LifecycleProjectEvaluator$EvaluateProject$1.run(LifecycleProjectEvaluator.java:109) at org.gradle.internal.Factories$1.create(Factories.java:26) at org.gradle.internal.work.DefaultWorkerLeaseService.withLocks(DefaultWorkerLeaseService.java:189) at org.gradle.internal.work.StopShieldingWorkerLeaseService.withLocks(StopShieldingWorkerLeaseService.java:40) at org.gradle.api.internal.project.DefaultProjectStateRegistry$ProjectStateImpl.withProjectLock(DefaultProjectStateRegistry.java:238) at org.gradle.api.internal.project.DefaultProjectStateRegistry$ProjectStateImpl.withMutableState(DefaultProjectStateRegistry.java:232) at org.gradle.api.internal.project.DefaultProjectStateRegistry$ProjectStateImpl.withMutableState(DefaultProjectStateRegistry.java:193) at org.gradle.configuration.project.LifecycleProjectEvaluator$EvaluateProject.run(LifecycleProjectEvaluator.java:96) at org.gradle.internal.operations.DefaultBuildOperationExecutor$RunnableBuildOperationWorker.execute(DefaultBuildOperationExecutor.java:402) at org.gradle.internal.operations.DefaultBuildOperationExecutor$RunnableBuildOperationWorker.execute(DefaultBuildOperationExecutor.java:394) at org.gradle.internal.operations.DefaultBuildOperationExecutor$1.execute(DefaultBuildOperationExecutor.java:165) at org.gradle.internal.operations.DefaultBuildOperationExecutor.execute(DefaultBuildOperationExecutor.java:250) at org.gradle.internal.operations.DefaultBuildOperationExecutor.execute(DefaultBuildOperationExecutor.java:158) at org.gradle.internal.operations.DefaultBuildOperationExecutor.run(DefaultBuildOperationExecutor.java:92) at org.gradle.internal.operations.DelegatingBuildOperationExecutor.run(DelegatingBuildOperationExecutor.java:31) at org.gradle.configuration.project.LifecycleProjectEvaluator.evaluate(LifecycleProjectEvaluator.java:68) at org.gradle.api.internal.project.DefaultProject.evaluate(DefaultProject.java:699) at org.gradle.api.internal.project.DefaultProject.evaluate(DefaultProject.java:142) at org.gradle.execution.TaskPathProjectEvaluator.configure(TaskPathProjectEvaluator.java:36) at org.gradle.execution.TaskPathProjectEvaluator.configureHierarchy(TaskPathProjectEvaluator.java:62) at org.gradle.configuration.DefaultProjectsPreparer.prepareProjects(DefaultProjectsPreparer.java:61) at org.gradle.configuration.BuildOperatingFiringProjectsPreparer$ConfigureBuild.run(BuildOperatingFiringProjectsPreparer.java:52) at org.gradle.internal.operations.DefaultBuildOperationExecutor$RunnableBuildOperationWorker.execute(DefaultBuildOperationExecutor.java:402) at org.gradle.internal.operations.DefaultBuildOperationExecutor$RunnableBuildOperationWorker.execute(DefaultBuildOperationExecutor.java:394) at org.gradle.internal.operations.DefaultBuildOperationExecutor$1.execute(DefaultBuildOperationExecutor.java:165) at org.gradle.internal.operations.DefaultBuildOperationExecutor.execute(DefaultBuildOperationExecutor.java:250) at org.gradle.internal.operations.DefaultBuildOperationExecutor.execute(DefaultBuildOperationExecutor.java:158) at org.gradle.internal.operations.DefaultBuildOperationExecutor.run(DefaultBuildOperationExecutor.java:92) at org.gradle.internal.operations.DelegatingBuildOperationExecutor.run(DelegatingBuildOperationExecutor.java:31) at org.gradle.configuration.BuildOperatingFiringProjectsPreparer.prepareProjects(BuildOperatingFiringProjectsPreparer.java:40) at org.gradle.initialization.DefaultGradleLauncher.prepareProjects(DefaultGradleLauncher.java:207) at org.gradle.initialization.DefaultGradleLauncher.doClassicBuildStages(DefaultGradleLauncher.java:145) at org.gradle.initialization.DefaultGradleLauncher.doBuildStages(DefaultGradleLauncher.java:130) at org.gradle.initialization.DefaultGradleLauncher.executeTasks(DefaultGradleLauncher.java:110) at org.gradle.internal.invocation.GradleBuildController$1.execute(GradleBuildController.java:60) at org.gradle.internal.invocation.GradleBuildController$1.execute(GradleBuildController.java:57) at org.gradle.internal.invocation.GradleBuildController$3.create(GradleBuildController.java:85) at org.gradle.internal.invocation.GradleBuildController$3.create(GradleBuildController.java:78) at org.gradle.internal.work.DefaultWorkerLeaseService.withLocks(DefaultWorkerLeaseService.java:189) at org.gradle.internal.work.StopShieldingWorkerLeaseService.withLocks(StopShieldingWorkerLeaseService.java:40) at org.gradle.internal.invocation.GradleBuildController.doBuild(GradleBuildController.java:78) at org.gradle.internal.invocation.GradleBuildController.run(GradleBuildController.java:57) at org.gradle.tooling.internal.provider.runner.ClientProvidedPhasedActionRunner.run(ClientProvidedPhasedActionRunner.java:60) at org.gradle.launcher.exec.ChainingBuildActionRunner.run(ChainingBuildActionRunner.java:35) at org.gradle.launcher.exec.ChainingBuildActionRunner.run(ChainingBuildActionRunner.java:35) at org.gradle.launcher.exec.BuildOutcomeReportingBuildActionRunner.run(BuildOutcomeReportingBuildActionRunner.java:63) at org.gradle.tooling.internal.provider.ValidatingBuildActionRunner.run(ValidatingBuildActionRunner.java:32) at org.gradle.launcher.exec.BuildCompletionNotifyingBuildActionRunner.run(BuildCompletionNotifyingBuildActionRunner.java:39) at org.gradle.launcher.exec.RunAsBuildOperationBuildActionRunner$3.call(RunAsBuildOperationBuildActionRunner.java:51) at org.gradle.launcher.exec.RunAsBuildOperationBuildActionRunner$3.call(RunAsBuildOperationBuildActionRunner.java:45) at org.gradle.internal.operations.DefaultBuildOperationExecutor$CallableBuildOperationWorker.execute(DefaultBuildOperationExecutor.java:416) at org.gradle.internal.operations.DefaultBuildOperationExecutor$CallableBuildOperationWorker.execute(DefaultBuildOperationExecutor.java:406) at org.gradle.internal.operations.DefaultBuildOperationExecutor$1.execute(DefaultBuildOperationExecutor.java:165) at org.gradle.internal.operations.DefaultBuildOperationExecutor.execute(DefaultBuildOperationExecutor.java:250) at org.gradle.internal.operations.DefaultBuildOperationExecutor.execute(DefaultBuildOperationExecutor.java:158) at org.gradle.internal.operations.DefaultBuildOperationExecutor.call(DefaultBuildOperationExecutor.java:102) at org.gradle.internal.operations.DelegatingBuildOperationExecutor.call(DelegatingBuildOperationExecutor.java:36) at org.gradle.launcher.exec.RunAsBuildOperationBuildActionRunner.run(RunAsBuildOperationBuildActionRunner.java:45) at org.gradle.launcher.exec.InProcessBuildActionExecuter$1.transform(InProcessBuildActionExecuter.java:50) at org.gradle.launcher.exec.InProcessBuildActionExecuter$1.transform(InProcessBuildActionExecuter.java:47) at org.gradle.composite.internal.DefaultRootBuildState.run(DefaultRootBuildState.java:80) at org.gradle.launcher.exec.InProcessBuildActionExecuter.execute(InProcessBuildActionExecuter.java:47) at org.gradle.launcher.exec.InProcessBuildActionExecuter.execute(InProcessBuildActionExecuter.java:31) at org.gradle.launcher.exec.BuildTreeScopeBuildActionExecuter.execute(BuildTreeScopeBuildActionExecuter.java:42) at org.gradle.launcher.exec.BuildTreeScopeBuildActionExecuter.execute(BuildTreeScopeBuildActionExecuter.java:28) at org.gradle.tooling.internal.provider.ContinuousBuildActionExecuter.execute(ContinuousBuildActionExecuter.java:78) at org.gradle.tooling.internal.provider.ContinuousBuildActionExecuter.execute(ContinuousBuildActionExecuter.java:52) at org.gradle.tooling.internal.provider.SubscribableBuildActionExecuter.execute(SubscribableBuildActionExecuter.java:60) at org.gradle.tooling.internal.provider.SubscribableBuildActionExecuter.execute(SubscribableBuildActionExecuter.java:38) at org.gradle.tooling.internal.provider.SessionScopeBuildActionExecuter.execute(SessionScopeBuildActionExecuter.java:68) at org.gradle.tooling.internal.provider.SessionScopeBuildActionExecuter.execute(SessionScopeBuildActionExecuter.java:38) at org.gradle.tooling.internal.provider.GradleThreadBuildActionExecuter.execute(GradleThreadBuildActionExecuter.java:37) at org.gradle.tooling.internal.provider.GradleThreadBuildActionExecuter.execute(GradleThreadBuildActionExecuter.java:26) at org.gradle.tooling.internal.provider.ParallelismConfigurationBuildActionExecuter.execute(ParallelismConfigurationBuildActionExecuter.java:43) at org.gradle.tooling.internal.provider.ParallelismConfigurationBuildActionExecuter.execute(ParallelismConfigurationBuildActionExecuter.java:29) at org.gradle.tooling.internal.provider.StartParamsValidatingActionExecuter.execute(StartParamsValidatingActionExecuter.java:60) at org.gradle.tooling.internal.provider.StartParamsValidatingActionExecuter.execute(StartParamsValidatingActionExecuter.java:32) at org.gradle.tooling.internal.provider.SessionFailureReportingActionExecuter.execute(SessionFailureReportingActionExecuter.java:55) at org.gradle.tooling.internal.provider.SessionFailureReportingActionExecuter.execute(SessionFailureReportingActionExecuter.java:41) at org.gradle.tooling.internal.provider.SetupLoggingActionExecuter.execute(SetupLoggingActionExecuter.java:48) at org.gradle.tooling.internal.provider.SetupLoggingActionExecuter.execute(SetupLoggingActionExecuter.java:32) at org.gradle.launcher.daemon.server.exec.ExecuteBuild.doBuild(ExecuteBuild.java:68) at org.gradle.launcher.daemon.server.exec.BuildCommandOnly.execute(BuildCommandOnly.java:37) at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:104) at org.gradle.launcher.daemon.server.exec.WatchForDisconnection.execute(WatchForDisconnection.java:39) at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:104) at org.gradle.launcher.daemon.server.exec.ResetDeprecationLogger.execute(ResetDeprecationLogger.java:27) at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:104) at org.gradle.launcher.daemon.server.exec.RequestStopIfSingleUsedDaemon.execute(RequestStopIfSingleUsedDaemon.java:35) at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:104) at org.gradle.launcher.daemon.server.exec.ForwardClientInput$2.create(ForwardClientInput.java:78) at org.gradle.launcher.daemon.server.exec.ForwardClientInput$2.create(ForwardClientInput.java:75) at org.gradle.util.Swapper.swap(Swapper.java:38) at org.gradle.launcher.daemon.server.exec.ForwardClientInput.execute(ForwardClientInput.java:75) at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:104) at org.gradle.launcher.daemon.server.exec.LogAndCheckHealth.execute(LogAndCheckHealth.java:55) at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:104) at org.gradle.launcher.daemon.server.exec.LogToClient.doBuild(LogToClient.java:63) at org.gradle.launcher.daemon.server.exec.BuildCommandOnly.execute(BuildCommandOnly.java:37) at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:104) at org.gradle.launcher.daemon.server.exec.EstablishBuildEnvironment.doBuild(EstablishBuildEnvironment.java:82) at org.gradle.launcher.daemon.server.exec.BuildCommandOnly.execute(BuildCommandOnly.java:37) at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:104) at org.gradle.launcher.daemon.server.exec.StartBuildOrRespondWithBusy$1.run(StartBuildOrRespondWithBusy.java:52) at org.gradle.launcher.daemon.server.DaemonStateCoordinator$1.run(DaemonStateCoordinator.java:297) at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:64) at org.gradle.internal.concurrent.ManagedExecutorImpl$1.run(ManagedExecutorImpl.java:48) at org.gradle.internal.concurrent.ThreadFactoryImpl$ManagedThreadRunnable.run(ThreadFactoryImpl.java:56) Caused by: org.gradle.api.internal.artifacts.ivyservice.DefaultLenientConfiguration$ArtifactResolveException: Could not resolve all artifacts for configuration ':classpath'. at org.gradle.api.internal.artifacts.configurations.DefaultConfiguration.rethrowFailure(DefaultConfiguration.java:1293) at org.gradle.api.internal.artifacts.configurations.DefaultConfiguration.access$2300(DefaultConfiguration.java:140) at org.gradle.api.internal.artifacts.configurations.DefaultConfiguration$ConfigurationArtifactCollection.ensureResolved(DefaultConfiguration.java:1780) at org.gradle.api.internal.artifacts.configurations.DefaultConfiguration$ConfigurationArtifactCollection.getArtifacts(DefaultConfiguration.java:1752) at org.gradle.composite.internal.CompositeBuildClassPathInitializer.execute(CompositeBuildClassPathInitializer.java:45) at org.gradle.composite.internal.CompositeBuildClassPathInitializer.execute(CompositeBuildClassPathInitializer.java:32) at org.gradle.api.internal.initialization.DefaultScriptClassPathResolver.resolveClassPath(DefaultScriptClassPathResolver.java:37) at org.gradle.api.internal.initialization.DefaultScriptHandler.getScriptClassPath(DefaultScriptHandler.java:87) at org.gradle.plugin.use.internal.DefaultPluginRequestApplicator.defineScriptHandlerClassScope(DefaultPluginRequestApplicator.java:210) at org.gradle.plugin.use.internal.DefaultPluginRequestApplicator.applyPlugins(DefaultPluginRequestApplicator.java:83) at org.gradle.configuration.DefaultScriptPluginFactory$ScriptPluginImpl.apply(DefaultScriptPluginFactory.java:216) at org.gradle.configuration.BuildOperationScriptPlugin$1$1.run(BuildOperationScriptPlugin.java:69) at org.gradle.internal.operations.DefaultBuildOperationExecutor$RunnableBuildOperationWorker.execute(DefaultBuildOperationExecutor.java:402) at org.gradle.internal.operations.DefaultBuildOperationExecutor$RunnableBuildOperationWorker.execute(DefaultBuildOperationExecutor.java:394) at org.gradle.internal.operations.DefaultBuildOperationExecutor$1.execute(DefaultBuildOperationExecutor.java:165) at org.gradle.internal.operations.DefaultBuildOperationExecutor.execute(DefaultBuildOperationExecutor.java:250) at org.gradle.internal.operations.DefaultBuildOperationExecutor.execute(DefaultBuildOperationExecutor.java:158) at org.gradle.internal.operations.DefaultBuildOperationExecutor.run(DefaultBuildOperationExecutor.java:92) at org.gradle.internal.operations.DelegatingBuildOperationExecutor.run(DelegatingBuildOperationExecutor.java:31) at org.gradle.configuration.BuildOperationScriptPlugin$1.execute(BuildOperationScriptPlugin.java:66) at org.gradle.configuration.BuildOperationScriptPlugin$1.execute(BuildOperationScriptPlugin.java:63) at org.gradle.configuration.internal.DefaultUserCodeApplicationContext.apply(DefaultUserCodeApplicationContext.java:49) at org.gradle.configuration.BuildOperationScriptPlugin.apply(BuildOperationScriptPlugin.java:63) at org.gradle.configuration.project.BuildScriptProcessor$1.run(BuildScriptProcessor.java:45) at org.gradle.internal.Factories$1.create(Factories.java:26) at org.gradle.api.internal.project.DefaultProjectStateRegistry$ProjectStateImpl.withMutableState(DefaultProjectStateRegistry.java:212) at org.gradle.api.internal.project.DefaultProjectStateRegistry$ProjectStateImpl.withMutableState(DefaultProjectStateRegistry.java:193) at org.gradle.configuration.project.BuildScriptProcessor.execute(BuildScriptProcessor.java:42) at org.gradle.configuration.project.BuildScriptProcessor.execute(BuildScriptProcessor.java:26) at org.gradle.configuration.project.ConfigureActionsProjectEvaluator.evaluate(ConfigureActionsProjectEvaluator.java:35) at org.gradle.configuration.project.LifecycleProjectEvaluator$EvaluateProject$1.run(LifecycleProjectEvaluator.java:107) ... 107 more Caused by: org.gradle.internal.resolve.ModuleVersionResolveException: Could not resolve com.android.tools.build:builder:4.0.0. Required by: project : > com.android.tools.build:gradle:4.0.0 Caused by: org.gradle.internal.resolve.ModuleVersionResolveException: Could not resolve com.android.tools.build:builder:4.0.0. Caused by: org.gradle.api.internal.artifacts.ivyservice.ivyresolve.parser.MetaDataParseException: Could not parse POM https://maven.aliyun.com/repository/google/com/android/tools/build/builder/4.0.0/builder-4.0.0.pom at org.gradle.api.internal.artifacts.ivyservice.ivyresolve.parser.PomReader$2.transform(PomReader.java:146) at org.gradle.api.internal.artifacts.ivyservice.ivyresolve.parser.PomReader$2.transform(PomReader.java:140) at org.gradle.internal.resource.local.LocalFileStandInExternalResource.withContentIfPresent(LocalFileStandInExternalResource.java:192) at org.gradle.internal.resource.AbstractExternalResource.withContent(AbstractExternalResource.java:40) at org.gradle.internal.resource.local.DefaultLocallyAvailableExternalResource.withContent(DefaultLocallyAvailableExternalResource.java:104) at org.gradle.api.internal.artifacts.ivyservice.ivyresolve.parser.PomReader.<init>(PomReader.java:140) at org.gradle.api.internal.artifacts.ivyservice.ivyresolve.parser.PomReader.<init>(PomReader.java:162) at org.gradle.api.internal.artifacts.ivyservice.ivyresolve.parser.GradlePomModuleDescriptorParser.doParseDescriptor(GradlePomModuleDescriptorParser.java:94) at org.gradle.api.internal.artifacts.ivyservice.ivyresolve.parser.AbstractModuleDescriptorParser.parseDescriptor(AbstractModuleDescriptorParser.java:50) at org.gradle.api.internal.artifacts.ivyservice.ivyresolve.parser.AbstractModuleDescriptorParser.parseMetaData(AbstractModuleDescriptorParser.java:45) at org.gradle.api.internal.artifacts.repositories.metadata.DefaultMavenPomMetadataSource.parseMetaDataFromResource(DefaultMavenPomMetadataSource.java:58) at org.gradle.api.internal.artifacts.repositories.metadata.AbstractRepositoryMetadataSource.parseMetaDataFromArtifact(AbstractRepositoryMetadataSource.java:81) at org.gradle.api.internal.artifacts.repositories.metadata.AbstractRepositoryMetadataSource.create(AbstractRepositoryMetadataSource.java:68) at org.gradle.api.internal.artifacts.repositories.metadata.DefaultMavenPomMetadataSource.create(DefaultMavenPomMetadataSource.java:40) at org.gradle.api.internal.artifacts.repositories.metadata.RedirectingGradleMetadataModuleMetadataSource.create(RedirectingGradleMetadataModuleMetadataSource.java:51) at org.gradle.api.internal.artifacts.repositories.resolver.ExternalResourceResolver.resolveStaticDependency(ExternalResourceResolver.java:252) at org.gradle.api.internal.artifacts.repositories.resolver.MavenResolver.doResolveComponentMetaData(MavenResolver.java:130) at org.gradle.api.internal.artifacts.repositories.resolver.ExternalResourceResolver$RemoteRepositoryAccess.resolveComponentMetaData(ExternalResourceResolver.java:479) at org.gradle.api.internal.artifacts.ivyservice.ivyresolve.CachingModuleComponentRepository$ResolveAndCacheRepositoryAccess.resolveComponentMetaData(CachingModuleComponentRepository.java:379) at org.gradle.api.internal.artifacts.ivyservice.ivyresolve.ErrorHandlingModuleComponentRepository$ErrorHandlingModuleComponentRepositoryAccess.lambda$resolveComponentMetaData$5(ErrorHandlingModuleComponentRepository.java:154) at org.gradle.api.internal.artifacts.ivyservice.ivyresolve.ErrorHandlingModuleComponentRepository$ErrorHandlingModuleComponentRepositoryAccess.lambda$tryResolveAndMaybeBlacklist$18(ErrorHandlingModuleComponentRepository.java:223) at org.gradle.api.internal.artifacts.ivyservice.ivyresolve.ErrorHandlingModuleComponentRepository$ErrorHandlingModuleComponentRepositoryAccess.tryResolveAndMaybeBlacklist(ErrorHandlingModuleComponentRepository.java:237) at org.gradle.api.internal.artifacts.ivyservice.ivyresolve.ErrorHandlingModuleComponentRepository$ErrorHandlingModuleComponentRepositoryAccess.tryResolveAndMaybeBlacklist(ErrorHandlingModuleComponentRepository.java:222) at org.gradle.api.internal.artifacts.ivyservice.ivyresolve.ErrorHandlingModuleComponentRepository$ErrorHandlingModuleComponentRepositoryAccess.performOperationWithRetries(ErrorHandlingModuleComponentRepository.java:215) at org.gradle.api.internal.artifacts.ivyservice.ivyresolve.ErrorHandlingModuleComponentRepository$ErrorHandlingModuleComponentRepositoryAccess.resolveComponentMetaData(ErrorHandlingModuleComponentRepository.java:153) at org.gradle.api.internal.artifacts.ivyservice.ivyresolve.ComponentMetaDataResolveState.process(ComponentMetaDataResolveState.java:69) at org.gradle.api.internal.artifacts.ivyservice.ivyresolve.ComponentMetaDataResolveState.resolve(ComponentMetaDataResolveState.java:61) at org.gradle.api.internal.artifacts.ivyservice.ivyresolve.RepositoryChainComponentMetaDataResolver.findBestMatch(RepositoryChainComponentMetaDataResolver.java:139) at org.gradle.api.internal.artifacts.ivyservice.ivyresolve.RepositoryChainComponentMetaDataResolver.findBestMatch(RepositoryChainComponentMetaDataResolver.java:120) at org.gradle.api.internal.artifacts.ivyservice.ivyresolve.RepositoryChainComponentMetaDataResolver.resolveModule(RepositoryChainComponentMetaDataResolver.java:93) at org.gradle.api.internal.artifacts.ivyservice.ivyresolve.RepositoryChainComponentMetaDataResolver.resolve(RepositoryChainComponentMetaDataResolver.java:64) at org.gradle.api.internal.artifacts.ivyservice.resolveengine.ComponentResolversChain$ComponentMetaDataResolverChain.resolve(ComponentResolversChain.java:95) at org.gradle.api.internal.artifacts.ivyservice.clientmodule.ClientModuleResolver.resolve(ClientModuleResolver.java:65) at org.gradle.api.internal.artifacts.ivyservice.resolveengine.graph.builder.ComponentState.resolve(ComponentState.java:195) at org.gradle.api.internal.artifacts.ivyservice.resolveengine.graph.builder.ComponentState.getMetadata(ComponentState.java:142) at org.gradle.api.internal.artifacts.ivyservice.resolveengine.graph.builder.DownloadMetadataOperation.run(DownloadMetadataOperation.java:31) at org.gradle.internal.operations.DefaultBuildOperationExecutor$RunnableBuildOperationWorker.execute(DefaultBuildOperationExecutor.java:402) at org.gradle.internal.operations.DefaultBuildOperationExecutor$RunnableBuildOperationWorker.execute(DefaultBuildOperationExecutor.java:394) at org.gradle.internal.operations.DefaultBuildOperationExecutor$1.execute(DefaultBuildOperationExecutor.java:165) at org.gradle.internal.operations.DefaultBuildOperationExecutor.execute(DefaultBuildOperationExecutor.java:250) at org.gradle.internal.operations.DefaultBuildOperationExecutor.execute(DefaultBuildOperationExecutor.java:158) at org.gradle.internal.operations.DefaultBuildOperationExecutor.access$1500(DefaultBuildOperationExecutor.java:49) at org.gradle.internal.operations.DefaultBuildOperationExecutor$ParentPreservingQueueWorker.execute(DefaultBuildOperationExecutor.java:444) at org.gradle.internal.operations.DefaultBuildOperationQueue$WorkerRunnable.runOperation(DefaultBuildOperationQueue.java:231) at org.gradle.internal.operations.DefaultBuildOperationQueue$WorkerRunnable.access$600(DefaultBuildOperationQueue.java:173) at org.gradle.internal.operations.DefaultBuildOperationQueue$WorkerRunnable$1.create(DefaultBuildOperationQueue.java:210) at org.gradle.internal.operations.DefaultBuildOperationQueue$WorkerRunnable$1.create(DefaultBuildOperationQueue.java:204) at org.gradle.internal.work.DefaultWorkerLeaseService.withLocks(DefaultWorkerLeaseService.java:189) at org.gradle.internal.operations.DefaultBuildOperationQueue$WorkerRunnable.runBatch(DefaultBuildOperationQueue.java:204) at org.gradle.internal.operations.DefaultBuildOperationQueue$WorkerRunnable.run(DefaultBuildOperationQueue.java:178) at org.gradle.internal.operations.DefaultBuildOperationQueue.waitForCompletion(DefaultBuildOperationQueue.java:117) at org.gradle.internal.operations.DefaultBuildOperationExecutor.executeInParallel(DefaultBuildOperationExecutor.java:144) at org.gradle.internal.operations.DefaultBuildOperationExecutor.runAll(DefaultBuildOperationExecutor.java:117) at org.gradle.internal.operations.DelegatingBuildOperationExecutor.runAll(DelegatingBuildOperationExecutor.java:46) at org.gradle.api.internal.artifacts.ivyservice.resolveengine.graph.builder.DependencyGraphBuilder.maybeDownloadMetadataInParallel(DependencyGraphBuilder.java:342) at org.gradle.api.internal.artifacts.ivyservice.resolveengine.graph.builder.DependencyGraphBuilder.resolveEdges(DependencyGraphBuilder.java:249) at org.gradle.api.internal.artifacts.ivyservice.resolveengine.graph.builder.DependencyGraphBuilder.traverseGraph(DependencyGraphBuilder.java:187) at org.gradle.api.internal.artifacts.ivyservice.resolveengine.graph.builder.DependencyGraphBuilder.resolve(DependencyGraphBuilder.java:146) at org.gradle.api.internal.artifacts.ivyservice.resolveengine.DefaultArtifactDependencyResolver.resolve(DefaultArtifactDependencyResolver.java:127) at org.gradle.api.internal.artifacts.ivyservice.DefaultConfigurationResolver.resolveGraph(DefaultConfigurationResolver.java:179) at org.gradle.api.internal.artifacts.ivyservice.ShortCircuitEmptyConfigurationResolver.resolveGraph(ShortCircuitEmptyConfigurationResolver.java:86) at org.gradle.api.internal.artifacts.ivyservice.ErrorHandlingConfigurationResolver.resolveGraph(ErrorHandlingConfigurationResolver.java:74) at org.gradle.api.internal.artifacts.configurations.DefaultConfiguration$6.run(DefaultConfiguration.java:632) at org.gradle.internal.operations.DefaultBuildOperationExecutor$RunnableBuildOperationWorker.execute(DefaultBuildOperationExecutor.java:402) at org.gradle.internal.operations.DefaultBuildOperationExecutor$RunnableBuildOperationWorker.execute(DefaultBuildOperationExecutor.java:394) at org.gradle.internal.operations.DefaultBuildOperationExecutor$1.execute(DefaultBuildOperationExecutor.java:165) at org.gradle.internal.operations.DefaultBuildOperationExecutor.execute(DefaultBuildOperationExecutor.java:250) at org.gradle.internal.operations.DefaultBuildOperationExecutor.execute(DefaultBuildOperationExecutor.java:158) at org.gradle.internal.operations.DefaultBuildOperationExecutor.run(DefaultBuildOperationExecutor.java:92) at org.gradle.internal.operations.DelegatingBuildOperationExecutor.run(DelegatingBuildOperationExecutor.java:31) at org.gradle.api.internal.artifacts.configurations.DefaultConfiguration.resolveGraphIfRequired(DefaultConfiguration.java:623) at org.gradle.api.internal.artifacts.configurations.DefaultConfiguration.access$500(DefaultConfiguration.java:140) at org.gradle.api.internal.artifacts.configurations.DefaultConfiguration$5.run(DefaultConfiguration.java:603) at org.gradle.api.internal.project.DefaultProjectStateRegistry$SafeExclusiveLockImpl.withLock(DefaultProjectStateRegistry.java:256) at org.gradle.api.internal.artifacts.configurations.DefaultConfiguration.resolveExclusively(DefaultConfiguration.java:599) at org.gradle.api.internal.artifacts.configurations.DefaultConfiguration.resolveToStateOrLater(DefaultConfiguration.java:588) at org.gradle.api.internal.artifacts.configurations.DefaultConfiguration.access$2400(DefaultConfiguration.java:140) at org.gradle.api.internal.artifacts.configurations.DefaultConfiguration$ConfigurationFileCollection.getSelectedArtifacts(DefaultConfiguration.java:1276) at org.gradle.api.internal.artifacts.configurations.DefaultConfiguration$ConfigurationFileCollection.access$3700(DefaultConfiguration.java:1193) at org.gradle.api.internal.artifacts.configurations.DefaultConfiguration$ConfigurationArtifactCollection.ensureResolved(DefaultConfiguration.java:1774) at org.gradle.api.internal.artifacts.configurations.DefaultConfiguration$ConfigurationArtifactCollection.getArtifacts(DefaultConfiguration.java:1752) at org.gradle.composite.internal.CompositeBuildClassPathInitializer.execute(CompositeBuildClassPathInitializer.java:45) at org.gradle.composite.internal.CompositeBuildClassPathInitializer.execute(CompositeBuildClassPathInitializer.java:32) at org.gradle.api.internal.initialization.DefaultScriptClassPathResolver.resolveClassPath(DefaultScriptClassPathResolver.java:37) at org.gradle.api.internal.initialization.DefaultScriptHandler.getScriptClassPath(DefaultScriptHandler.java:87) at org.gradle.plugin.use.internal.DefaultPluginRequestApplicator.defineScriptHandlerClassScope(DefaultPluginRequestApplicator.java:210) at org.gradle.plugin.use.internal.DefaultPluginRequestApplicator.applyPlugins(DefaultPluginRequestApplicator.java:83) at org.gradle.configuration.DefaultScriptPluginFactory$ScriptPluginImpl.apply(DefaultScriptPluginFactory.java:216) at org.gradle.configuration.BuildOperationScriptPlugin$1$1.run(BuildOperationScriptPlugin.java:69) at org.gradle.internal.operations.DefaultBuildOperationExecutor$RunnableBuildOperationWorker.execute(DefaultBuildOperationExecutor.java:402) at org.gradle.internal.operations.DefaultBuildOperationExecutor$RunnableBuildOperationWorker.execute(DefaultBuildOperationExecutor.java:394) at org.gradle.internal.operations.DefaultBuildOperationExecutor$1.execute(DefaultBuildOperationExecutor.java:165) at org.gradle.internal.operations.DefaultBuildOperationExecutor.execute(DefaultBuildOperationExecutor.java:250) at org.gradle.internal.operations.DefaultBuildOperationExecutor.execute(DefaultBuildOperationExecutor.java:158) at org.gradle.internal.operations.DefaultBuildOperationExecutor.run(DefaultBuildOperationExecutor.java:92) at org.gradle.internal.operations.DelegatingBuildOperationExecutor.run(DelegatingBuildOperationExecutor.java:31) at org.gradle.configuration.BuildOperationScriptPlugin$1.execute(BuildOperationScriptPlugin.java:66) at org.gradle.configuration.BuildOperationScriptPlugin$1.execute(BuildOperationScriptPlugin.java:63) at org.gradle.configuration.internal.DefaultUserCodeApplicationContext.apply(DefaultUserCodeApplicationContext.java:49) at org.gradle.configuration.BuildOperationScriptPlugin.apply(BuildOperationScriptPlugin.java:63) at org.gradle.configuration.project.BuildScriptProcessor$1.run(BuildScriptProcessor.java:45) at org.gradle.internal.Factories$1.create(Factories.java:26) at org.gradle.api.internal.project.DefaultProjectStateRegistry$ProjectStateImpl.withMutableState(DefaultProjectStateRegistry.java:212) at org.gradle.api.internal.project.DefaultProjectStateRegistry$ProjectStateImpl.withMutableState(DefaultProjectStateRegistry.java:193) at org.gradle.configuration.project.BuildScriptProcessor.execute(BuildScriptProcessor.java:42) at org.gradle.configuration.project.BuildScriptProcessor.execute(BuildScriptProcessor.java:26) at org.gradle.configuration.project.ConfigureActionsProjectEvaluator.evaluate(ConfigureActionsProjectEvaluator.java:35) at org.gradle.configuration.project.LifecycleProjectEvaluator$EvaluateProject$1.run(LifecycleProjectEvaluator.java:107) at org.gradle.internal.Factories$1.create(Factories.java:26) at org.gradle.internal.work.DefaultWorkerLeaseService.withLocks(DefaultWorkerLeaseService.java:189) at org.gradle.internal.work.StopShieldingWorkerLeaseService.withLocks(StopShieldingWorkerLeaseService.java:40) at org.gradle.api.internal.project.DefaultProjectStateRegistry$ProjectStateImpl.withProjectLock(DefaultProjectStateRegistry.java:238) at org.gradle.api.internal.project.DefaultProjectStateRegistry$ProjectStateImpl.withMutableState(DefaultProjectStateRegistry.java:232) at org.gradle.api.internal.project.DefaultProjectStateRegistry$ProjectStateImpl.withMutableState(DefaultProjectStateRegistry.java:193) at org.gradle.configuration.project.LifecycleProjectEvaluator$EvaluateProject.run(LifecycleProjectEvaluator.java:96) at org.gradle.internal.operations.DefaultBuildOperationExecutor$RunnableBuildOperationWorker.execute(DefaultBuildOperationExecutor.java:402) at org.gradle.internal.operations.DefaultBuildOperationExecutor$RunnableBuildOperationWorker.execute(DefaultBuildOperationExecutor.java:394) at org.gradle.internal.operations.DefaultBuildOperationExecutor$1.execute(DefaultBuildOperationExecutor.java:165) at org.gradle.internal.operations.DefaultBuildOperationExecutor.execute(DefaultBuildOperationExecutor.java:250) at org.gradle.internal.operations.DefaultBuildOperationExecutor.execute(DefaultBuildOperationExecutor.java:158) at org.gradle.internal.operations.DefaultBuildOperationExecutor.run(DefaultBuildOperationExecutor.java:92) at org.gradle.internal.operations.DelegatingBuildOperationExecutor.run(DelegatingBuildOperationExecutor.java:31) at org.gradle.configuration.project.LifecycleProjectEvaluator.evaluate(LifecycleProjectEvaluator.java:68) at org.gradle.api.internal.project.DefaultProject.evaluate(DefaultProject.java:699) at org.gradle.api.internal.project.DefaultProject.evaluate(DefaultProject.java:142) at org.gradle.execution.TaskPathProjectEvaluator.configure(TaskPathProjectEvaluator.java:36) at org.gradle.execution.TaskPathProjectEvaluator.configureHierarchy(TaskPathProjectEvaluator.java:62) at org.gradle.configuration.DefaultProjectsPreparer.prepareProjects(DefaultProjectsPreparer.java:61) at org.gradle.configuration.BuildOperatingFiringProjectsPreparer$ConfigureBuild.run(BuildOperatingFiringProjectsPreparer.java:52) at org.gradle.internal.operations.DefaultBuildOperationExecutor$RunnableBuildOperationWorker.execute(DefaultBuildOperationExecutor.java:402) at org.gradle.internal.operations.DefaultBuildOperationExecutor$RunnableBuildOperationWorker.execute(DefaultBuildOperationExecutor.java:394) at org.gradle.internal.operations.DefaultBuildOperationExecutor$1.execute(DefaultBuildOperationExecutor.java:165) at org.gradle.internal.operations.DefaultBuildOperationExecutor.execute(DefaultBuildOperationExecutor.java:250) at org.gradle.internal.operations.DefaultBuildOperationExecutor.execute(DefaultBuildOperationExecutor.java:158) at org.gradle.internal.operations.DefaultBuildOperationExecutor.run(DefaultBuildOperationExecutor.java:92) at org.gradle.internal.operations.DelegatingBuildOperationExecutor.run(DelegatingBuildOperationExecutor.java:31) at org.gradle.configuration.BuildOperatingFiringProjectsPreparer.prepareProjects(BuildOperatingFiringProjectsPreparer.java:40) at org.gradle.initialization.DefaultGradleLauncher.prepareProjects(DefaultGradleLauncher.java:207) at org.gradle.initialization.DefaultGradleLauncher.doClassicBuildStages(DefaultGradleLauncher.java:145) at org.gradle.initialization.DefaultGradleLauncher.doBuildStages(DefaultGradleLauncher.java:130) at org.gradle.initialization.DefaultGradleLauncher.executeTasks(DefaultGradleLauncher.java:110) at org.gradle.internal.invocation.GradleBuildController$1.execute(GradleBuildController.java:60) at org.gradle.internal.invocation.GradleBuildController$1.execute(GradleBuildController.java:57) at org.gradle.internal.invocation.GradleBuildController$3.create(GradleBuildController.java:85) at org.gradle.internal.invocation.GradleBuildController$3.create(GradleBuildController.java:78) at org.gradle.internal.work.DefaultWorkerLeaseService.withLocks(DefaultWorkerLeaseService.java:189) at org.gradle.internal.work.StopShieldingWorkerLeaseService.withLocks(StopShieldingWorkerLeaseService.java:40) at org.gradle.internal.invocation.GradleBuildController.doBuild(GradleBuildController.java:78) at org.gradle.internal.invocation.GradleBuildController.run(GradleBuildController.java:57) at org.gradle.tooling.internal.provider.runner.ClientProvidedPhasedActionRunner.run(ClientProvidedPhasedActionRunner.java:60) at org.gradle.launcher.exec.ChainingBuildActionRunner.run(ChainingBuildActionRunner.java:35) at org.gradle.launcher.exec.ChainingBuildActionRunner.run(ChainingBuildActionRunner.java:35) at org.gradle.launcher.exec.BuildOutcomeReportingBuildActionRunner.run(BuildOutcomeReportingBuildActionRunner.java:63) at org.gradle.tooling.internal.provider.ValidatingBuildActionRunner.run(ValidatingBuildActionRunner.java:32) at org.gradle.launcher.exec.BuildCompletionNotifyingBuildActionRunner.run(BuildCompletionNotifyingBuildActionRunner.java:39) at org.gradle.launcher.exec.RunAsBuildOperationBuildActionRunner$3.call(RunAsBuildOperationBuildActionRunner.java:51) at org.gradle.launcher.exec.RunAsBuildOperationBuildActionRunner$3.call(RunAsBuildOperationBuildActionRunner.java:45) at org.gradle.internal.operations.DefaultBuildOperationExecutor$CallableBuildOperationWorker.execute(DefaultBuildOperationExecutor.java:416) at org.gradle.internal.operations.DefaultBuildOperationExecutor$CallableBuildOperationWorker.execute(DefaultBuildOperationExecutor.java:406) at org.gradle.internal.operations.DefaultBuildOperationExecutor$1.execute(DefaultBuildOperationExecutor.java:165) at org.gradle.internal.operations.DefaultBuildOperationExecutor.execute(DefaultBuildOperationExecutor.java:250) at org.gradle.internal.operations.DefaultBuildOperationExecutor.execute(DefaultBuildOperationExecutor.java:158) at org.gradle.internal.operations.DefaultBuildOperationExecutor.call(DefaultBuildOperationExecutor.java:102) at org.gradle.internal.operations.DelegatingBuildOperationExecutor.call(DelegatingBuildOperationExecutor.java:36) at org.gradle.launcher.exec.RunAsBuildOperationBuildActionRunner.run(RunAsBuildOperationBuildActionRunner.java:45) at org.gradle.launcher.exec.InProcessBuildActionExecuter$1.transform(InProcessBuildActionExecuter.java:50) at org.gradle.launcher.exec.InProcessBuildActionExecuter$1.transform(InProcessBuildActionExecuter.java:47) at org.gradle.composite.internal.DefaultRootBuildState.run(DefaultRootBuildState.java:80) at org.gradle.launcher.exec.InProcessBuildActionExecuter.execute(InProcessBuildActionExecuter.java:47) at org.gradle.launcher.exec.InProcessBuildActionExecuter.execute(InProcessBuildActionExecuter.java:31) at org.gradle.launcher.exec.BuildTreeScopeBuildActionExecuter.execute(BuildTreeScopeBuildActionExecuter.java:42) at org.gradle.launcher.exec.BuildTreeScopeBuildActionExecuter.execute(BuildTreeScopeBuildActionExecuter.java:28) at org.gradle.tooling.internal.provider.ContinuousBuildActionExecuter.execute(ContinuousBuildActionExecuter.java:78) at org.gradle.tooling.internal.provider.ContinuousBuildActionExecuter.execute(ContinuousBuildActionExecuter.java:52) at org.gradle.tooling.internal.provider.SubscribableBuildActionExecuter.execute(SubscribableBuildActionExecuter.java:60) at org.gradle.tooling.internal.provider.SubscribableBuildActionExecuter.execute(SubscribableBuildActionExecuter.java:38) at org.gradle.tooling.internal.provider.SessionScopeBuildActionExecuter.execute(SessionScopeBuildActionExecuter.java:68) at org.gradle.tooling.internal.provider.SessionScopeBuildActionExecuter.execute(SessionScopeBuildActionExecuter.java:38) at org.gradle.tooling.internal.provider.GradleThreadBuildActionExecuter.execute(GradleThreadBuildActionExecuter.java:37) at org.gradle.tooling.internal.provider.GradleThreadBuildActionExecuter.execute(GradleThreadBuildActionExecuter.java:26) at org.gradle.tooling.internal.provider.ParallelismConfigurationBuildActionExecuter.execute(ParallelismConfigurationBuildActionExecuter.java:43) at org.gradle.tooling.internal.provider.ParallelismConfigurationBuildActionExecuter.execute(ParallelismConfigurationBuildActionExecuter.java:29) at org.gradle.tooling.internal.provider.StartParamsValidatingActionExecuter.execute(StartParamsValidatingActionExecuter.java:60) at org.gradle.tooling.internal.provider.StartParamsValidatingActionExecuter.execute(StartParamsValidatingActionExecuter.java:32) at org.gradle.tooling.internal.provider.SessionFailureReportingActionExecuter.execute(SessionFailureReportingActionExecuter.java:55) at org.gradle.tooling.internal.provider.SessionFailureReportingActionExecuter.execute(SessionFailureReportingActionExecuter.java:41) at org.gradle.tooling.internal.provider.SetupLoggingActionExecuter.execute(SetupLoggingActionExecuter.java:48) at org.gradle.tooling.internal.provider.SetupLoggingActionExecuter.execute(SetupLoggingActionExecuter.java:32) at org.gradle.launcher.daemon.server.exec.ExecuteBuild.doBuild(ExecuteBuild.java:68) at org.gradle.launcher.daemon.server.exec.BuildCommandOnly.execute(BuildCommandOnly.java:37) at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:104) at org.gradle.launcher.daemon.server.exec.WatchForDisconnection.execute(WatchForDisconnection.java:39) at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:104) at org.gradle.launcher.daemon.server.exec.ResetDeprecationLogger.execute(ResetDeprecationLogger.java:27) at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:104) at org.gradle.launcher.daemon.server.exec.RequestStopIfSingleUsedDaemon.execute(RequestStopIfSingleUsedDaemon.java:35) at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:104) at org.gradle.launcher.daemon.server.exec.ForwardClientInput$2.create(ForwardClientInput.java:78) at org.gradle.launcher.daemon.server.exec.ForwardClientInput$2.create(ForwardClientInput.java:75) at org.gradle.util.Swapper.swap(Swapper.java:38) at org.gradle.launcher.daemon.server.exec.ForwardClientInput.execute(ForwardClientInput.java:75) at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:104) at org.gradle.launcher.daemon.server.exec.LogAndCheckHealth.execute(LogAndCheckHealth.java:55) at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:104) at org.gradle.launcher.daemon.server.exec.LogToClient.doBuild(LogToClient.java:63) at org.gradle.launcher.daemon.server.exec.BuildCommandOnly.execute(BuildCommandOnly.java:37) at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:104) at org.gradle.launcher.daemon.server.exec.EstablishBuildEnvironment.doBuild(EstablishBuildEnvironment.java:82) at org.gradle.launcher.daemon.server.exec.BuildCommandOnly.execute(BuildCommandOnly.java:37) at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:104) at org.gradle.launcher.daemon.server.exec.StartBuildOrRespondWithBusy$1.run(StartBuildOrRespondWithBusy.java:52) at org.gradle.launcher.daemon.server.DaemonStateCoordinator$1.run(DaemonStateCoordinator.java:297) at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:64) at org.gradle.internal.concurrent.ManagedExecutorImpl$1.run(ManagedExecutorImpl.java:48) at org.gradle.internal.concurrent.ThreadFactoryImpl$ManagedThreadRunnable.run(ThreadFactoryImpl.java:56) Caused by: org.xml.sax.SAXParseException; systemId: file:/home/anson/.gradle/caches/modules-2/files-2.1/com.android.tools.build/builder/4.0.0/ea102cc3f0b98305689d0f1bd3ed97c889c6ea17/builder-4.0.0.pom; lineNumber: 1; columnNumber: 44; 前言中不允许有内容。 at com.sun.org.apache.xerces.internal.parsers.DOMParser.parse(DOMParser.java:257) at com.sun.org.apache.xerces.internal.jaxp.DocumentBuilderImpl.parse(DocumentBuilderImpl.java:339) at org.gradle.api.internal.artifacts.ivyservice.ivyresolve.parser.PomReader.parseToDom(PomReader.java:258) at org.gradle.api.internal.artifacts.ivyservice.ivyresolve.parser.PomReader.access$100(PomReader.java:60) at org.gradle.api.internal.artifacts.ivyservice.ivyresolve.parser.PomReader$2.transform(PomReader.java:144) ... 214 more * Get more help at https://help.gradle.org BUILD FAILED in 932ms解决改回使用google()repositories { google() //maven { url 'https://maven.aliyun.com/repository/google' } maven { url 'https://maven.aliyun.com/repository/jcenter' } }不解, 坐等大神不吝解答引用(不适用,供参考)解决:gradle 前言中不允许有内容Android Studio Error:前言中不允许有内容Android studio中出现“前言中不允许有内容”错误是什么原因?android studio 前言中不允许有内容
环境笔记本: 机械师创物者M 144Hz设计笔记本电脑十代i7-10875H/RTX2060独显轻薄全面屏游戏本 标配16G/512G PCIE高速固态加装1T SSD: 西部数据(Western Digital)1TB SSD固态硬盘 M.2接口(NVMe协议) WD_BLACK SN750游戏高性能版五年质保Download Ubuntu Desktop默认已装好WIN10, UBUNTU将会装在加装的1T SSD上.安装Ubuntu参考:ACER Nitro AN515-54 WIN10 + Ubuntu 16.04双系统创物者M的BIOS键是 F2修改完BOOT选项, 保存并生效 F4其它的安装流程与上文一致安装完成后, 可以更改BIOS设置由WIN10或UBUNTU引导, 从UBUNTU引导, 可以有菜单选择进哪个系统PS: 来来回回装了Ubuntu 18.04和Ubuntu 20.04不下10回, 当然, 非笔记本问题, 更多是在软件兼容性和环境配置上, 有问题的U盘也相当坑.环境安装五笔输入法极点五笔for Ubuntu安装(不生效)Ubuntu输入法设置不能保存VirtualBox不管是从官网下载安装, 还是从软件中心安装, 以下方法均无效如何在 Ubuntu 中修复 VirtualBox 的 “Kernel driver not installed (rc=-1908)” 错Kernel driver not installed (rc=-1908) error in VirtualBox [duplicate]How to sign a kernel module Ubuntu 18.04How To Fix “Kernel driver not installed (rc=-1908)” VirtualBox Error In UbuntuHow to fix ‘modprobe vboxdrv’ error in virtualBox?抛开以上种种问题, 回归本质, 请在BIOS中关闭Secure Boot接下来就简单多了通过软件中心搜索并安装VirtualBox, 版本: 6.1.10_Ubuntu r138449从VirtualBox官网下载对应的6.1.10版本的扩展包, 双击安装上即可USB访问: sudo addgroup myusername vboxusers装完虚拟系统后, 安装设备 > 安装增强功能Android Studio(此方法在后续重装后已不需要, 具体原因未知)Android Studio /dev/kvm device : permision denied解决办法在WIN10中, 除了系统分区外, 还有一个DATA分区, 想把它挂载到Ubuntu上, 发现这个分区不可写入解决Ubuntu 20.04挂载NTFS分区不能写入(只读权限)的问题美化Ubuntu增大屏幕可用面积之——自动隐藏顶部状态栏VIM 中文乱码Ubuntu16.04 vim中文乱码创建应用图标, 以AndroidStudio为例anson@anson-MR26:/home$ cat /usr/share/applications/as.desktop [Desktop Entry] Type=Application Name=AndroidStudio Comment=Android Studio 4.1 Icon=/work/devEnv/android-studio/bin/studio.png Exec=/work/devEnv/android-studio/bin/studio.sh Terminal=false Categories=Development;IDE;Java;GNOME;GTK; StartupWMClass=jetbrains-studio重启后生效Ubuntu 18.04收藏夹同一程序两个图标问题编译Android编译android 7.1 kernel 失败, 主要是由于python版本的问题/work/codes/rk3288_n712/u-boot/lib/optee_clientApi/tabinary_to_cfile.py --prefix keymaster --TA lib/optee_clientApi/258be795-f9ca-40e6-a8699ce6886c5d5d.ta --out lib/optee_clientApi/258be795-f9ca-40e6-a8699ce6886c5d5d.c CC lib/optee_clientApi/OpteeClientRkFs.o /usr/bin/env: “python”: 没有那个文件或目录 make[2]: *** [/work/codes/rk3288_n712/u-boot/lib/optee_clientApi/Makefile:18:lib/optee_clientApi/258be795-f9ca-40e6-a8699ce6886c5d5d.c] 错误 127 make[2]: *** 正在等待未完成的任务.... LD lib/libfdt/built-in.o lib/optee_clientApi/OpteeClientInterface.c: In function 'test_optee': lib/optee_clientApi/OpteeClientInterface.c:35:2: warning: implicit declaration of function 'StorageGetBootMedia' [-Wimplicit-function-declaration] if (StorageGetBootMedia() == BOOT_FROM_EMMC) { ^ make[1]: *** [scripts/Makefile.build:422:lib/optee_clientApi] 错误 2 make: *** [Makefile:1184:lib] 错误 2 make: *** 正在等待未完成的任务.... LD drivers/video/built-in.o LD drivers/built-in.o INFO: start build kernel HOSTCC scripts/basic/fixdep HOSTCC scripts/kconfig/conf.o HOSTCC scripts/kconfig/zconf.tab.o HOSTLD scripts/kconfig/conf # # configuration written to .config # /usr/bin/env: “python”: 没有那个文件或目录 scripts/kconfig/conf --silentoldconfig Kconfig Makefile:717: Cannot use CONFIG_CC_STACKPROTECTOR_STRONG: -fstack-protector-strong not supported by compiler /usr/bin/env: “python”: 没有那个文件或目录感觉是python的问题, 试了下python命令, 提示找不到anson@anson-MR26:/work/codes/Builder$ python Command 'python' not found, did you mean: command 'python3' from deb python3 command 'python' from deb python-is-python3#创建软链 ln -sf /usr/bin/python3 /usr/bin/python/work/codes/rk3288_n712/u-boot/lib/optee_clientApi/tabinary_to_cfile.py --prefix keymaster --TA lib/optee_clientApi/258be795-f9ca-40e6-a8699ce6886c5d5d.ta --out lib/optee_clientApi/258be795-f9ca-40e6-a8699ce6886c5d5d.c LD common/built-in.o Traceback (most recent call last): File "/work/codes/rk3288_n712/u-boot/lib/optee_clientApi/tabinary_to_cfile.py", line 58, in <module> main() File "/work/codes/rk3288_n712/u-boot/lib/optee_clientApi/tabinary_to_cfile.py", line 31, in main TAdata = f.read() File "/usr/lib/python3.8/codecs.py", line 322, in decode (result, consumed) = self._buffer_decode(data, self.errors, final) UnicodeDecodeError: 'utf-8' codec can't decode byte 0xa3 in position 20: invalid start byte make[2]: *** [/work/codes/rk3288_n712/u-boot/lib/optee_clientApi/Makefile:18:lib/optee_clientApi/258be795-f9ca-40e6-a8699ce6886c5d5d.c] 错误 1 make[1]: *** [scripts/Makefile.build:422:lib/optee_clientApi] 错误 2 make: *** [Makefile:1184:lib] 错误 2找了另一台电脑查了下版本, 用的是2.7.#创建软链 ln -sf /usr/bin/python2.7 /usr/bin/python再编, 通过!android make 失败prebuilts/clang/host/linux-x86/clang-2690385/bin/clang++ -fno-exceptions -Wno-multichar -m64 -Wa,--noexecstack -fPIC -no-canonical-prefixes -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=2 -fstack-protector -D__STDC_FORMAT_MACROS -D__STDC_CONSTANT_MACROS -DANDROID -fmessage-length=0 -W -Wall -Wno-unused -Winit-self -Wpointer-arith -O2 -g -fno-strict-aliasing -DNDEBUG -UDEBUG -D__compiler_offsetof=__builtin_offsetof -Wno-reserved-id-macro -Wno-format-pedantic -Wno-unused-command-line-argument --gcc-toolchain=prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.15-4.8 -fstack-protector-strong --gcc-toolchain=prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.15-4.8 --sysroot prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.15-4.8/sysroot -Bprebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.15-4.8/x86_64-linux/bin -target x86_64-linux-gnu -Wsign-promo -Wno-inconsistent-missing-override --gcc-toolchain=prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.15-4.8 --sysroot prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.15-4.8/sysroot -isystem prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.15-4.8/x86_64-linux/include/c++/4.8 -isystem prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.15-4.8/x86_64-linux/include/c++/4.8/x86_64-linux -isystem prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.15-4.8/x86_64-linux/include/c++/4.8/backward -target x86_64-linux-gnu -c -std=c++11 -g -W -Wall -MMD -MP -O -DNOLOG -march=native -o out/host/linux-x86/obj/EXECUTABLES/ckati_intermediates/affinity.o build/kati/affinity.cc prebuilts/clang/host/linux-x86/clang-2690385/bin/clang++: error while loading shared libraries: libncurses.so.5: cannot open shared object file: No such file or directory make: *** [build/kati/Makefile.ckati:89:out/host/linux-x86/obj/EXECUTABLES/ckati_intermediates/affinity.o] 错误 127 #### make failed to build some targets ####解决: error while loading shared libraries: libncurses.so.5:sudo apt-get install libncurses5[ 1% 598/36361] Lex: aidl <= system/tools/aidl/aidl_language_l.ll FAILED: /bin/bash -c "prebuilts/misc/linux-x86/flex/flex-2.5.39 -oout/host/linux-x86/obj/STATIC_LIBRARIES/libaidl-common_intermediates/aidl_language_l.cpp system/tools/aidl/aidl_language_l.ll" flex-2.5.39: loadlocale.c:130:_nl_intern_locale_data: ?? 'cnt < (sizeof (_nl_value_type_LC_TIME) / sizeof (_nl_value_type_LC_TIME[0]))' ??? Aborted (core dumped)解决:android8.1编译错误flex-2.5.39: loadlocale.c:130:_nl_intern_locale_data:~/.bashrc, 加上最后一行# enable programmable completion features (you don't need to enable # this, if it's already enabled in /etc/bash.bashrc and /etc/profile # sources /etc/bash.bashrc). if ! shopt -oq posix; then if [ -f /usr/share/bash-completion/bash_completion ]; then . /usr/share/bash-completion/bash_completion elif [ -f /etc/bash_completion ]; then . /etc/bash_completion fi fi export LC_ALL=C执行source ~/.bashrc+++++++++++++++++++++++++++++++++注意注意+++++++++++++++++++++++++++++++++关于export LC_ALL=C 请慎用, 在后续使用过程中, 发现加上后会导致终端中无法正常显示和输入中文---------------------------------------------------------注意注意------------------------------------------------------------命令记录#JDK sudo add-apt-repository ppa:openjdk-r/ppa sudo apt-get update sudo apt-get install openjdk-7-jdk sudo apt-get install openjdk-8-jdk sudo apt-get install vim sudo apt-get install minicom #追加源 sudo echo "deb http://us.archive.ubuntu.com/ubuntu trusty main universe" >> /etc/apt/sources.list sudo apt-get update #安装依赖 sudo apt-get install git gnupg flex bison gperf build-essential zip curl libc6-dev libncurses5-dev:i386 x11proto-core-dev libx11-dev:i386 libreadline6-dev:i386 libgl1-mesa-glx:i386 libgl1-mesa-dev g++-multilib tofrodos python-markdown libxml2-utils xsltproc zlib1g-dev:i386 sudo apt-get install lzop libncurses5 sudo ln -s /usr/lib/i386-linux-gnu/mesa/libGL.so.1 /usr/lib/i386-linux-gnu/libGL.so sudo apt-get install mingw32 sudo apt-get install automake make perl gcc g++ #SSH 服务端 sudo apt-get install openssh-server chrome-gnome-shell #输入法 sudo apt install fcitx-bin #VirtualBox 访问U盘 sudo addgroup anson vboxusers #Android编译环境补充 sudo ln -sf /usr/bin/python2.7 /usr/bin/python echo "export LC_ALL=C" >> ~/.bashrc source .bashrc完成
TensorFlow LiteTensorFlow Lite 是一种用于设备端推断的开源深度学习框架,在移动设备和 IoT 设备上部署机器学习模型环境AndroidStudio 4.0 + JAVA数字分类器通过 TensorFlow Lite 模型对手写数字进行分类。关于DEMOGithub demo 源码(kotlin)上面图片的DEMO Github demo 源码(Java)历程刚开始并没有找到图片中的DEMO源码, 于是自己根据kotlin的DEMO移植了一下, 以下是移植的过程, 若对TensorFlow Lite已有所了解, 请自行跳过.在AS中新建Module DigitClassifierByTFL.编译环境build.gradle中SDK相关配置:android { compileSdkVersion 30 buildToolsVersion "30.0.2" defaultConfig { applicationId "com.ansondroider.digitclassifierbytfl" minSdkVersion 16 targetSdkVersion 16 versionCode 1 versionName "1.0" } }目录结构等待构建完成, 需修改一些配置:build.gradle: 不压缩 .tflite 文件, 若不加会因为导入模型有问题导致运行出错aaptOptions { noCompress "tflite" }build.gradle: 增加 TensorFlow Lite依赖dependencies { implementation fileTree(dir: "libs", include: ["*.jar"]) implementation ('org.tensorflow:tensorflow-lite:0.0.0-nightly'){changing = true} }源码及说明layout<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent"> <com.ansondroider.digitclassifierbytfl.PaintView android:layout_width="400dp" android:layout_height="400dp" android:layout_centerHorizontal="true" android:id="@+id/paintView"/> <TextView android:id="@+id/tvRes" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_alignParentBottom="true" android:textColor="#FF00FF00" android:text="Result: ?" android:textSize="30sp"/> </RelativeLayout>PaintView: 手指绘画.TextView: 显示结果.Activitypackage com.ansondroider.digitclassifierbytfl; import android.Manifest; import android.app.Activity; import android.content.res.AssetFileDescriptor; import android.content.res.AssetManager; import android.graphics.Bitmap; import android.os.Build; import android.os.Bundle; import android.widget.TextView; import org.tensorflow.lite.Interpreter; import java.io.FileInputStream; import java.io.IOException; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.nio.channels.FileChannel; public class DigitClassifierByTFL extends Activity { PaintView paintView; TextView tvRes; Classifier fier; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); //初始化UI setContentView(R.layout.activity_digit_classifier_by_tfl); tvRes = (TextView)findViewById(R.id.tvRes); paintView = (PaintView)findViewById(R.id.paintView); //添加PaintView回调, 当手指绘画完成后, 立即调用分类器进行分类. //绘画完成: 当手指抬起后 500 毫秒. paintView.setCallback(new PaintView.Callback() { @Override public void onWriteDone() { final String res = fier.classifier(paintView.getBitmap()); tvRes.post(new Runnable() { @Override public void run() { tvRes.setText(res); } }); } }); //创建分类器 fier = new Classifier(getAssets()); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { requestPermissions(new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.READ_EXTERNAL_STORAGE}, 0x77); } } @Override protected void onDestroy() { super.onDestroy(); fier.close(); }PaintViewpackage com.ansondroider.digitclassifierbytfl; import android.content.Context; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.Path; import android.util.AttributeSet; import android.view.MotionEvent; import android.view.View; public class PaintView extends View { public PaintView(Context context) { super(context); } public PaintView(Context context, AttributeSet attrs) { super(context, attrs); } public PaintView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } Bitmap bm; public Bitmap getBitmap(){ return bm; } @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { super.onSizeChanged(w, h, oldw, oldh); if(bm != null){ bm.recycle(); } bm = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888); cBm = new Canvas(bm); cBm.drawColor(Color.BLACK); } Canvas cBm; Paint p = new Paint(Paint.ANTI_ALIAS_FLAG); float dx, dy, cx, cy; @Override public boolean onTouchEvent(MotionEvent event) { cx = event.getX(); cy = event.getY(); switch(event.getAction()){ case MotionEvent.ACTION_DOWN: dx = cx; dy = cy; startWrite(); break; case MotionEvent.ACTION_MOVE: onMove(); break; case MotionEvent.ACTION_CANCEL: case MotionEvent.ACTION_UP: endWrite(); break; } postInvalidate(); return true; } Path path = new Path(); void startWrite(){ removeCallbacks(writeDone); path.moveTo(cx, cy); //cBm.drawColor(Color.WHITE); } void onMove(){ path.lineTo(cx, cy); cBm.drawColor(Color.BLACK); p.setStyle(Paint.Style.STROKE); p.setColor(Color.WHITE); p.setStrokeWidth(50); cBm.drawPath(path, p); } Runnable writeDone = new Runnable() { @Override public void run() { if(cb != null)cb.onWriteDone(); path.reset(); } }; void endWrite(){ removeCallbacks(writeDone); postDelayed(writeDone, 500); } @Override protected void onDraw(Canvas canvas) { if(bm != null && !bm.isRecycled())canvas.drawBitmap(bm, 0, 0, p); } Callback cb; public void setCallback(Callback c){ cb = c; } public interface Callback{ void onWriteDone(); } }分类器class Classifier{ //mnist.tflite: 来自kotlin DEMO, 识别率很低, 文件小. //mnist_big.tflite: 来自JAVA DEMO, 识别率高,文件大 final String MODEL = "mnist_big.tflite"; //插入器 Interpreter interpreter; //输入识别的图像尺寸 int bmWidth, bmHeight; //用于读取tflite文件 AssetManager asset; //用于创建ByteBuffer int modelInputSize; Classifier(AssetManager asset){ this.asset = asset; //创建插入器. Interpreter.Options op = new Interpreter.Options(); op.setUseNNAPI(true); interpreter = new Interpreter(loadModel(), op); //获取输入信息 int[] shape = interpreter.getInputTensor(0).shape(); bmWidth = shape[1]; bmHeight = shape[2]; //计算ByteBuffer大小. int FLOAT_TYPE_SIZE = 4; int PIXEL_SIZE = 1; modelInputSize = FLOAT_TYPE_SIZE * bmWidth * bmHeight * PIXEL_SIZE; } //加载模型 ByteBuffer loadModel(){ try { AssetFileDescriptor fd = asset.openFd(MODEL); FileInputStream is = new FileInputStream(fd.getFileDescriptor()); FileChannel channel = is.getChannel(); long startOffset = fd.getStartOffset(); long declareLength = fd.getDeclaredLength(); return channel.map(FileChannel.MapMode.READ_ONLY, startOffset, declareLength); } catch (IOException e) { e.printStackTrace(); } return null; } //执行分类 String classifier(Bitmap bm){ //缩放图片到指定尺寸.(28*28) Bitmap nbm = Bitmap.createScaledBitmap(bm, bmWidth, bmHeight, true); ByteBuffer byteBuffer = convertBitmapToByteBuffer(nbm); //Kotlin中的代码: // val result = Array(1) { FloatArray(OUTPUT_CLASSES_COUNT) } // 平时不用它, 看这代码头痛了好久. //若创建的数组不对, 如用float[10], 或float[2][10] //则会导致异常(Google 百度都不知道): /** 2020-09-10 10:55:18.213 14429-14429/com.ansondroider.digitclassifierbytfl E/AndroidRuntime: FATAL EXCEPTION: main Process: com.ansondroider.digitclassifierbytfl, PID: 14429 java.lang.IllegalArgumentException: Cannot copy from a TensorFlowLite tensor (softmax_tensor) with shape [1, 10] to a Java object with shape [2, 10]. at org.tensorflow.lite.Tensor.throwIfDstShapeIsIncompatible(Tensor.java:482) at org.tensorflow.lite.Tensor.copyTo(Tensor.java:252) at org.tensorflow.lite.NativeInterpreterWrapper.run(NativeInterpreterWrapper.java:170) at org.tensorflow.lite.Interpreter.runForMultipleInputsOutputs(Interpreter.java:347) at org.tensorflow.lite.Interpreter.run(Interpreter.java:306) at com.ansondroider.digitclassifierbytfl.DigitClassifierByTFL$Classifier.classifier(DigitClassifierByTFL.java:98) at com.ansondroider.digitclassifierbytfl.DigitClassifierByTFL$1.onWriteDone(DigitClassifierByTFL.java:33) at com.ansondroider.digitclassifierbytfl.PaintView$1.run(PaintView.java:86) at android.os.Handler.handleCallback(Handler.java:883) at android.os.Handler.dispatchMessage(Handler.java:100) at android.os.Looper.loop(Looper.java:214) at android.app.ActivityThread.main(ActivityThread.java:7356) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:930)**/ float[][] result = new float[1][10]; //执行. interpreter.run(byteBuffer, result); //格式化输出 return getOutputSting(result); } String getOutputSting(float[][] floats){ //Kotlin 代码: // val maxIndex = output.indices.maxBy { output[it] } ?: -1 // return "Prediction Result: %d\nConfidence: %2f".format(maxIndex, output[maxIndex]) //在float[10]数组中, 存放了推算的结果, 下标分别对应的是[0,9]的数字. //只需要遍历10个数中, 找出最大的值即可. StringBuilder result = new StringBuilder("Result:\n"); float[] res = floats[0]; float max = -1; int v = -1; for(int i = 0; i < res.length; i ++){ result.append("[" + i + "]=" + res[i]).append("\n"); if(max < res[i]){ max = res[i]; v = i; } } result.append("BEST: " + v); return result.toString(); } ByteBuffer convertBitmapToByteBuffer(Bitmap bm){ //刚开始, 用错了函数接口: ByteBuffer.allocate //这样会导致推算的结果不管输入如何变化, 都输出固定的float[10] //在打开后一直不变, 而在调试过程中, 也出现过多次生新运行都显示同样的结果. ByteBuffer bf = ByteBuffer.allocateDirect(modelInputSize); bf.order(ByteOrder.nativeOrder()); int[] pixels = new int[bmWidth * bmHeight]; bm.getPixels(pixels, 0, bm.getWidth(), 0, 0, bm.getWidth(), bm.getHeight()); for(int i = 0; i < pixels.length; i ++){ int r = (pixels[i] >> 16) & 0xFF; int g = (pixels[i] >> 8) & 0xFF; int b = pixels[i] & 0xFF; float normalizePixelValue = (r + g + b) / 3f / 255f; bf.putFloat(normalizePixelValue); } return bf; } void close(){ interpreter.close(); } } }DEMODemo源码下载相关TensorFlow Lite(Jinpeng)TensorFlow Lite 指南TensorFlow Lite 示例应用Kotlin入门(4)声明与操作数组Kotlin Arraygoogle / tensorflow / tensorflow-lite
平台RK3288 + Android 7.1需求修改系统源码, 通过Intent附带参数, 支持自动点击安装下一步, 调用代码Intent install = new Intent(Intent.ACTION_VIEW); install.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); File apkFile = new File(Environment.getExternalStorageDirectory() + "/download/" + "app.apk"; install.putExtra("confirm", true); install.setDataAndType(Uri.fromFile(apkFile)), "application/vnd.android.package-archive"); startActivity(install)补丁diff --git a/packages/apps/PackageInstaller/src/com/android/packageinstaller/PackageInstallerActivity.java b/packages/apps/PackageInstaller/src/com/android/packageinstaller/PackageInstallerActivity.java index e600dd8..f6cf2c7 100644 --- a/packages/apps/PackageInstaller/src/com/android/packageinstaller/PackageInstallerActivity.java +++ b/packages/apps/PackageInstaller/src/com/android/packageinstaller/PackageInstallerActivity.java @@ -564,6 +564,12 @@ public class PackageInstallerActivity extends Activity implements OnCancelListen } else { initiateInstall(); } + // add confirm extra for install package. + boolean confirm = intent.getBooleanExtra("confirm", true); + if(!confirm){ + mOkCanInstall = true; + onClick(mOk); + } } /** Get the ApplicationInfo for the calling package, if available */修改后源码文件/* ** ** Copyright 2007, 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.packageinstaller; import android.app.Activity; import android.app.ActivityManagerNative; import android.app.AlertDialog; import android.app.Dialog; import android.content.Context; import android.content.DialogInterface; import android.content.DialogInterface.OnCancelListener; import android.content.Intent; import android.content.SharedPreferences; import android.content.pm.ApplicationInfo; import android.content.pm.ManifestDigest; import android.content.pm.PackageInfo; import android.content.pm.PackageInstaller; import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; import android.content.pm.PackageParser; import android.content.pm.PackageUserState; import android.content.pm.ResolveInfo; import android.content.pm.VerificationParams; import android.net.Uri; import android.os.Bundle; import android.os.SystemClock; import android.os.UserManager; import android.provider.Settings; import android.support.v4.view.ViewPager; import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.View.OnClickListener; import android.view.ViewGroup; import android.widget.AppSecurityPermissions; import android.widget.Button; import android.widget.TabHost; import android.widget.TextView; import java.io.File; import java.util.List; /* * This activity is launched when a new application is installed via side loading * The package is first parsed and the user is notified of parse errors via a dialog. * If the package is successfully parsed, the user is notified to turn on the install unknown * applications setting. A memory check is made at this point and the user is notified of out * of memory conditions if any. If the package is already existing on the device, * a confirmation dialog (to replace the existing package) is presented to the user. * Based on the user response the package is then installed by launching InstallAppConfirm * sub activity. All state transitions are handled in this activity */ public class PackageInstallerActivity extends Activity implements OnCancelListener, OnClickListener { private static final String TAG = "PackageInstaller"; private int mSessionId = -1; private Uri mPackageURI; private Uri mOriginatingURI; private Uri mReferrerURI; private int mOriginatingUid = VerificationParams.NO_UID; private ManifestDigest mPkgDigest; private boolean localLOGV = false; PackageManager mPm; UserManager mUserManager; PackageInstaller mInstaller; PackageInfo mPkgInfo; ApplicationInfo mSourceInfo; // ApplicationInfo object primarily used for already existing applications private ApplicationInfo mAppInfo = null; private InstallFlowAnalytics mInstallFlowAnalytics; // View for install progress View mInstallConfirm; // Buttons to indicate user acceptance private Button mOk; private Button mCancel; CaffeinatedScrollView mScrollView = null; private boolean mOkCanInstall = false; static final String PREFS_ALLOWED_SOURCES = "allowed_sources"; private static final String PACKAGE_MIME_TYPE = "application/vnd.android.package-archive"; private static final String TAB_ID_ALL = "all"; private static final String TAB_ID_NEW = "new"; // Dialog identifiers used in showDialog private static final int DLG_BASE = 0; private static final int DLG_UNKNOWN_SOURCES = DLG_BASE + 1; private static final int DLG_PACKAGE_ERROR = DLG_BASE + 2; private static final int DLG_OUT_OF_SPACE = DLG_BASE + 3; private static final int DLG_INSTALL_ERROR = DLG_BASE + 4; private static final int DLG_ALLOW_SOURCE = DLG_BASE + 5; private static final int DLG_ADMIN_RESTRICTS_UNKNOWN_SOURCES = DLG_BASE + 6; private void startInstallConfirm() { TabHost tabHost = (TabHost)findViewById(android.R.id.tabhost); tabHost.setup(); ViewPager viewPager = (ViewPager)findViewById(R.id.pager); TabsAdapter adapter = new TabsAdapter(this, tabHost, viewPager); adapter.setOnTabChangedListener(new TabHost.OnTabChangeListener() { @Override public void onTabChanged(String tabId) { if (TAB_ID_ALL.equals(tabId)) { mInstallFlowAnalytics.setAllPermissionsDisplayed(true); } else if (TAB_ID_NEW.equals(tabId)) { mInstallFlowAnalytics.setNewPermissionsDisplayed(true); } } }); boolean permVisible = false; mScrollView = null; mOkCanInstall = false; int msg = 0; if (mPkgInfo != null) { AppSecurityPermissions perms = new AppSecurityPermissions(this, mPkgInfo); final int NP = perms.getPermissionCount(AppSecurityPermissions.WHICH_PERSONAL); final int ND = perms.getPermissionCount(AppSecurityPermissions.WHICH_DEVICE); if (mAppInfo != null) { msg = (mAppInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0 ? R.string.install_confirm_question_update_system : R.string.install_confirm_question_update; mScrollView = new CaffeinatedScrollView(this); mScrollView.setFillViewport(true); boolean newPermissionsFound = (perms.getPermissionCount(AppSecurityPermissions.WHICH_NEW) > 0); mInstallFlowAnalytics.setNewPermissionsFound(newPermissionsFound); if (newPermissionsFound) { permVisible = true; mScrollView.addView(perms.getPermissionsView( AppSecurityPermissions.WHICH_NEW)); } else { LayoutInflater inflater = (LayoutInflater)getSystemService( Context.LAYOUT_INFLATER_SERVICE); TextView label = (TextView)inflater.inflate(R.layout.label, null); label.setText(R.string.no_new_perms); mScrollView.addView(label); } adapter.addTab(tabHost.newTabSpec(TAB_ID_NEW).setIndicator( getText(R.string.newPerms)), mScrollView); } else { findViewById(R.id.tabscontainer).setVisibility(View.GONE); findViewById(R.id.divider).setVisibility(View.VISIBLE); } if (NP > 0 || ND > 0) { permVisible = true; LayoutInflater inflater = (LayoutInflater)getSystemService( Context.LAYOUT_INFLATER_SERVICE); View root = inflater.inflate(R.layout.permissions_list, null); if (mScrollView == null) { mScrollView = (CaffeinatedScrollView)root.findViewById(R.id.scrollview); } if (NP > 0) { ((ViewGroup)root.findViewById(R.id.privacylist)).addView( perms.getPermissionsView(AppSecurityPermissions.WHICH_PERSONAL)); } else { root.findViewById(R.id.privacylist).setVisibility(View.GONE); } if (ND > 0) { ((ViewGroup)root.findViewById(R.id.devicelist)).addView( perms.getPermissionsView(AppSecurityPermissions.WHICH_DEVICE)); } else { root.findViewById(R.id.devicelist).setVisibility(View.GONE); } adapter.addTab(tabHost.newTabSpec(TAB_ID_ALL).setIndicator( getText(R.string.allPerms)), root); } } mInstallFlowAnalytics.setPermissionsDisplayed(permVisible); if (!permVisible) { if (mAppInfo != null) { // This is an update to an application, but there are no // permissions at all. msg = (mAppInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0 ? R.string.install_confirm_question_update_system_no_perms : R.string.install_confirm_question_update_no_perms; } else { // This is a new application with no permissions. msg = R.string.install_confirm_question_no_perms; } tabHost.setVisibility(View.GONE); mInstallFlowAnalytics.setAllPermissionsDisplayed(false); mInstallFlowAnalytics.setNewPermissionsDisplayed(false); findViewById(R.id.filler).setVisibility(View.VISIBLE); findViewById(R.id.divider).setVisibility(View.GONE); mScrollView = null; } if (msg != 0) { ((TextView)findViewById(R.id.install_confirm_question)).setText(msg); } mInstallConfirm.setVisibility(View.VISIBLE); mOk = (Button)findViewById(R.id.ok_button); mCancel = (Button)findViewById(R.id.cancel_button); mOk.setOnClickListener(this); mCancel.setOnClickListener(this); if (mScrollView == null) { // There is nothing to scroll view, so the ok button is immediately // set to install. mOk.setText(R.string.install); mOkCanInstall = true; } else { mScrollView.setFullScrollAction(new Runnable() { @Override public void run() { mOk.setText(R.string.install); mOkCanInstall = true; } }); } } private void showDialogInner(int id) { // TODO better fix for this? Remove dialog so that it gets created again removeDialog(id); showDialog(id); } @Override public Dialog onCreateDialog(int id, Bundle bundle) { switch (id) { case DLG_UNKNOWN_SOURCES: return new AlertDialog.Builder(this) .setTitle(R.string.unknown_apps_dlg_title) .setMessage(R.string.unknown_apps_dlg_text) .setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) { Log.i(TAG, "Finishing off activity so that user can navigate to settings manually"); finish(); }}) .setPositiveButton(R.string.settings, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) { Log.i(TAG, "Launching settings"); launchSettingsAppAndFinish(); } }) .setOnCancelListener(this) .create(); case DLG_ADMIN_RESTRICTS_UNKNOWN_SOURCES: return new AlertDialog.Builder(this) .setTitle(R.string.unknown_apps_dlg_title) .setMessage(R.string.unknown_apps_admin_dlg_text) .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) { finish(); } }) .setOnCancelListener(this) .create(); case DLG_PACKAGE_ERROR : return new AlertDialog.Builder(this) .setTitle(R.string.Parse_error_dlg_title) .setMessage(R.string.Parse_error_dlg_text) .setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) { finish(); } }) .setOnCancelListener(this) .create(); case DLG_OUT_OF_SPACE: // Guaranteed not to be null. will default to package name if not set by app CharSequence appTitle = mPm.getApplicationLabel(mPkgInfo.applicationInfo); String dlgText = getString(R.string.out_of_space_dlg_text, appTitle.toString()); return new AlertDialog.Builder(this) .setTitle(R.string.out_of_space_dlg_title) .setMessage(dlgText) .setPositiveButton(R.string.manage_applications, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) { //launch manage applications Intent intent = new Intent("android.intent.action.MANAGE_PACKAGE_STORAGE"); intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); startActivity(intent); finish(); } }) .setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) { Log.i(TAG, "Canceling installation"); finish(); } }) .setOnCancelListener(this) .create(); case DLG_INSTALL_ERROR : // Guaranteed not to be null. will default to package name if not set by app CharSequence appTitle1 = mPm.getApplicationLabel(mPkgInfo.applicationInfo); String dlgText1 = getString(R.string.install_failed_msg, appTitle1.toString()); return new AlertDialog.Builder(this) .setTitle(R.string.install_failed) .setNeutralButton(R.string.ok, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) { finish(); } }) .setMessage(dlgText1) .setOnCancelListener(this) .create(); case DLG_ALLOW_SOURCE: CharSequence appTitle2 = mPm.getApplicationLabel(mSourceInfo); String dlgText2 = getString(R.string.allow_source_dlg_text, appTitle2.toString()); return new AlertDialog.Builder(this) .setTitle(R.string.allow_source_dlg_title) .setMessage(dlgText2) .setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) { setResult(RESULT_CANCELED); finish(); }}) .setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) { SharedPreferences prefs = getSharedPreferences(PREFS_ALLOWED_SOURCES, Context.MODE_PRIVATE); prefs.edit().putBoolean(mSourceInfo.packageName, true).apply(); startInstallConfirm(); } }) .setOnCancelListener(this) .create(); } return null; } private void launchSettingsAppAndFinish() { // Create an intent to launch SettingsTwo activity Intent launchSettingsIntent = new Intent(Settings.ACTION_SECURITY_SETTINGS); launchSettingsIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); startActivity(launchSettingsIntent); finish(); } private boolean isInstallRequestFromUnknownSource(Intent intent) { String callerPackage = getCallingPackage(); if (callerPackage != null && intent.getBooleanExtra( Intent.EXTRA_NOT_UNKNOWN_SOURCE, false)) { try { mSourceInfo = mPm.getApplicationInfo(callerPackage, 0); if (mSourceInfo != null) { if ((mSourceInfo.flags & ApplicationInfo.FLAG_PRIVILEGED) != 0) { // Privileged apps are not considered an unknown source. return false; } } } catch (NameNotFoundException e) { } } return true; } private boolean isVerifyAppsEnabled() { if (mUserManager.hasUserRestriction(UserManager.ENSURE_VERIFY_APPS)) { return true; } return Settings.Global.getInt(getContentResolver(), Settings.Global.PACKAGE_VERIFIER_ENABLE, 1) > 0; } private boolean isAppVerifierInstalled() { final PackageManager pm = getPackageManager(); final Intent verification = new Intent(Intent.ACTION_PACKAGE_NEEDS_VERIFICATION); verification.setType(PACKAGE_MIME_TYPE); verification.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); final List<ResolveInfo> receivers = pm.queryBroadcastReceivers(verification, 0); return (receivers.size() > 0) ? true : false; } /** * @return whether unknown sources is enabled by user in Settings */ private boolean isUnknownSourcesEnabled() { return Settings.Secure.getInt(getContentResolver(), Settings.Secure.INSTALL_NON_MARKET_APPS, 0) > 0; } /** * @return whether the device admin restricts installation from unknown sources */ private boolean isUnknownSourcesAllowedByAdmin() { return !mUserManager.hasUserRestriction(UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES); } private void initiateInstall() { String pkgName = mPkgInfo.packageName; // Check if there is already a package on the device with this name // but it has been renamed to something else. String[] oldName = mPm.canonicalToCurrentPackageNames(new String[] { pkgName }); if (oldName != null && oldName.length > 0 && oldName[0] != null) { pkgName = oldName[0]; mPkgInfo.packageName = pkgName; mPkgInfo.applicationInfo.packageName = pkgName; } // Check if package is already installed. display confirmation dialog if replacing pkg try { // This is a little convoluted because we want to get all uninstalled // apps, but this may include apps with just data, and if it is just // data we still want to count it as "installed". mAppInfo = mPm.getApplicationInfo(pkgName, PackageManager.GET_UNINSTALLED_PACKAGES); if ((mAppInfo.flags&ApplicationInfo.FLAG_INSTALLED) == 0) { mAppInfo = null; } } catch (NameNotFoundException e) { mAppInfo = null; } mInstallFlowAnalytics.setReplace(mAppInfo != null); mInstallFlowAnalytics.setSystemApp( (mAppInfo != null) && ((mAppInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0)); startInstallConfirm(); } void setPmResult(int pmResult) { Intent result = new Intent(); result.putExtra(Intent.EXTRA_INSTALL_RESULT, pmResult); setResult(pmResult == PackageManager.INSTALL_SUCCEEDED ? RESULT_OK : RESULT_FIRST_USER, result); } @Override protected void onCreate(Bundle icicle) { super.onCreate(icicle); mPm = getPackageManager(); mInstaller = mPm.getPackageInstaller(); mUserManager = (UserManager) getSystemService(Context.USER_SERVICE); final Intent intent = getIntent(); if (PackageInstaller.ACTION_CONFIRM_PERMISSIONS.equals(intent.getAction())) { final int sessionId = intent.getIntExtra(PackageInstaller.EXTRA_SESSION_ID, -1); final PackageInstaller.SessionInfo info = mInstaller.getSessionInfo(sessionId); if (info == null || !info.sealed || info.resolvedBaseCodePath == null) { Log.w(TAG, "Session " + mSessionId + " in funky state; ignoring"); finish(); return; } mSessionId = sessionId; mPackageURI = Uri.fromFile(new File(info.resolvedBaseCodePath)); mOriginatingURI = null; mReferrerURI = null; } else { mSessionId = -1; mPackageURI = intent.getData(); mOriginatingURI = intent.getParcelableExtra(Intent.EXTRA_ORIGINATING_URI); mReferrerURI = intent.getParcelableExtra(Intent.EXTRA_REFERRER); } final boolean unknownSourcesAllowedByAdmin = isUnknownSourcesAllowedByAdmin(); final boolean unknownSourcesAllowedByUser = isUnknownSourcesEnabled(); boolean requestFromUnknownSource = isInstallRequestFromUnknownSource(intent); mInstallFlowAnalytics = new InstallFlowAnalytics(); mInstallFlowAnalytics.setContext(this); mInstallFlowAnalytics.setStartTimestampMillis(SystemClock.elapsedRealtime()); mInstallFlowAnalytics.setInstallsFromUnknownSourcesPermitted(unknownSourcesAllowedByAdmin && unknownSourcesAllowedByUser); mInstallFlowAnalytics.setInstallRequestFromUnknownSource(requestFromUnknownSource); mInstallFlowAnalytics.setVerifyAppsEnabled(isVerifyAppsEnabled()); mInstallFlowAnalytics.setAppVerifierInstalled(isAppVerifierInstalled()); mInstallFlowAnalytics.setPackageUri(mPackageURI.toString()); final String scheme = mPackageURI.getScheme(); if (scheme != null && !"file".equals(scheme) && !"package".equals(scheme)) { Log.w(TAG, "Unsupported scheme " + scheme); setPmResult(PackageManager.INSTALL_FAILED_INVALID_URI); mInstallFlowAnalytics.setFlowFinished( InstallFlowAnalytics.RESULT_FAILED_UNSUPPORTED_SCHEME); finish(); return; } final PackageUtil.AppSnippet as; if ("package".equals(mPackageURI.getScheme())) { mInstallFlowAnalytics.setFileUri(false); try { mPkgInfo = mPm.getPackageInfo(mPackageURI.getSchemeSpecificPart(), PackageManager.GET_PERMISSIONS | PackageManager.GET_UNINSTALLED_PACKAGES); } catch (NameNotFoundException e) { } if (mPkgInfo == null) { Log.w(TAG, "Requested package " + mPackageURI.getScheme() + " not available. Discontinuing installation"); showDialogInner(DLG_PACKAGE_ERROR); setPmResult(PackageManager.INSTALL_FAILED_INVALID_APK); mInstallFlowAnalytics.setPackageInfoObtained(); mInstallFlowAnalytics.setFlowFinished( InstallFlowAnalytics.RESULT_FAILED_PACKAGE_MISSING); return; } as = new PackageUtil.AppSnippet(mPm.getApplicationLabel(mPkgInfo.applicationInfo), mPm.getApplicationIcon(mPkgInfo.applicationInfo)); } else { mInstallFlowAnalytics.setFileUri(true); final File sourceFile = new File(mPackageURI.getPath()); PackageParser.Package parsed = PackageUtil.getPackageInfo(sourceFile); // Check for parse errors if (parsed == null) { Log.w(TAG, "Parse error when parsing manifest. Discontinuing installation"); showDialogInner(DLG_PACKAGE_ERROR); setPmResult(PackageManager.INSTALL_FAILED_INVALID_APK); mInstallFlowAnalytics.setPackageInfoObtained(); mInstallFlowAnalytics.setFlowFinished( InstallFlowAnalytics.RESULT_FAILED_TO_GET_PACKAGE_INFO); return; } mPkgInfo = PackageParser.generatePackageInfo(parsed, null, PackageManager.GET_PERMISSIONS, 0, 0, null, new PackageUserState()); mPkgDigest = parsed.manifestDigest; as = PackageUtil.getAppSnippet(this, mPkgInfo.applicationInfo, sourceFile); } mInstallFlowAnalytics.setPackageInfoObtained(); //set view setContentView(R.layout.install_start); mInstallConfirm = findViewById(R.id.install_confirm_panel); mInstallConfirm.setVisibility(View.INVISIBLE); PackageUtil.initSnippetForNewApp(this, as, R.id.app_snippet); mOriginatingUid = getOriginatingUid(intent); // Block the install attempt on the Unknown Sources setting if necessary. if (!requestFromUnknownSource) { initiateInstall(); return; } // If the admin prohibits it, or we're running in a managed profile, just show error // and exit. Otherwise show an option to take the user to Settings to change the setting. final boolean isManagedProfile = mUserManager.isManagedProfile(); if (!unknownSourcesAllowedByAdmin || (!unknownSourcesAllowedByUser && isManagedProfile)) { showDialogInner(DLG_ADMIN_RESTRICTS_UNKNOWN_SOURCES); mInstallFlowAnalytics.setFlowFinished( InstallFlowAnalytics.RESULT_BLOCKED_BY_UNKNOWN_SOURCES_SETTING); } else if (!unknownSourcesAllowedByUser) { // Ask user to enable setting first showDialogInner(DLG_UNKNOWN_SOURCES); mInstallFlowAnalytics.setFlowFinished( InstallFlowAnalytics.RESULT_BLOCKED_BY_UNKNOWN_SOURCES_SETTING); } else { initiateInstall(); } //add confirm extra for install package. boolean confirm = intent.getBooleanExtra("confirm", true); if(!confirm){ mOkCanInstall = true; onClick(mOk); } } /** Get the ApplicationInfo for the calling package, if available */ private ApplicationInfo getSourceInfo() { String callingPackage = getCallingPackage(); if (callingPackage != null) { try { return mPm.getApplicationInfo(callingPackage, 0); } catch (NameNotFoundException ex) { // ignore } } return null; } /** Get the originating uid if possible, or VerificationParams.NO_UID if not available */ private int getOriginatingUid(Intent intent) { // The originating uid from the intent. We only trust/use this if it comes from a // system application int uidFromIntent = intent.getIntExtra(Intent.EXTRA_ORIGINATING_UID, VerificationParams.NO_UID); // Get the source info from the calling package, if available. This will be the // definitive calling package, but it only works if the intent was started using // startActivityForResult, ApplicationInfo sourceInfo = getSourceInfo(); if (sourceInfo != null) { if (uidFromIntent != VerificationParams.NO_UID && (mSourceInfo.flags & ApplicationInfo.FLAG_PRIVILEGED) != 0) { return uidFromIntent; } // We either didn't get a uid in the intent, or we don't trust it. Use the // uid of the calling package instead. return sourceInfo.uid; } // We couldn't get the specific calling package. Let's get the uid instead int callingUid; try { callingUid = ActivityManagerNative.getDefault() .getLaunchedFromUid(getActivityToken()); } catch (android.os.RemoteException ex) { Log.w(TAG, "Could not determine the launching uid."); // nothing else we can do return VerificationParams.NO_UID; } // If we got a uid from the intent, we need to verify that the caller is a // privileged system package before we use it if (uidFromIntent != VerificationParams.NO_UID) { String[] callingPackages = mPm.getPackagesForUid(callingUid); if (callingPackages != null) { for (String packageName: callingPackages) { try { ApplicationInfo applicationInfo = mPm.getApplicationInfo(packageName, 0); if ((applicationInfo.flags & ApplicationInfo.FLAG_PRIVILEGED) != 0) { return uidFromIntent; } } catch (NameNotFoundException ex) { // ignore it, and try the next package } } } } // We either didn't get a uid from the intent, or we don't trust it. Use the // calling uid instead. return callingUid; } @Override public void onBackPressed() { if (mSessionId != -1) { mInstaller.setPermissionsResult(mSessionId, false); } mInstallFlowAnalytics.setFlowFinished( InstallFlowAnalytics.RESULT_CANCELLED_BY_USER); super.onBackPressed(); } // Generic handling when pressing back key public void onCancel(DialogInterface dialog) { finish(); } public void onClick(View v) { if (v == mOk) { if (mOkCanInstall || mScrollView == null) { mInstallFlowAnalytics.setInstallButtonClicked(); if (mSessionId != -1) { mInstaller.setPermissionsResult(mSessionId, true); // We're only confirming permissions, so we don't really know how the // story ends; assume success. mInstallFlowAnalytics.setFlowFinishedWithPackageManagerResult( PackageManager.INSTALL_SUCCEEDED); } else { // Start subactivity to actually install the application Intent newIntent = new Intent(); newIntent.putExtra(PackageUtil.INTENT_ATTR_APPLICATION_INFO, mPkgInfo.applicationInfo); newIntent.setData(mPackageURI); newIntent.setClass(this, InstallAppProgress.class); newIntent.putExtra(InstallAppProgress.EXTRA_MANIFEST_DIGEST, mPkgDigest); newIntent.putExtra( InstallAppProgress.EXTRA_INSTALL_FLOW_ANALYTICS, mInstallFlowAnalytics); String installerPackageName = getIntent().getStringExtra( Intent.EXTRA_INSTALLER_PACKAGE_NAME); if (mOriginatingURI != null) { newIntent.putExtra(Intent.EXTRA_ORIGINATING_URI, mOriginatingURI); } if (mReferrerURI != null) { newIntent.putExtra(Intent.EXTRA_REFERRER, mReferrerURI); } if (mOriginatingUid != VerificationParams.NO_UID) { newIntent.putExtra(Intent.EXTRA_ORIGINATING_UID, mOriginatingUid); } if (installerPackageName != null) { newIntent.putExtra(Intent.EXTRA_INSTALLER_PACKAGE_NAME, installerPackageName); } if (getIntent().getBooleanExtra(Intent.EXTRA_RETURN_RESULT, false)) { newIntent.putExtra(Intent.EXTRA_RETURN_RESULT, true); newIntent.addFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT); } if(localLOGV) Log.i(TAG, "downloaded app uri="+mPackageURI); startActivity(newIntent); } finish(); } else { mScrollView.pageScroll(View.FOCUS_DOWN); } } else if(v == mCancel) { // Cancel and finish setResult(RESULT_CANCELED); if (mSessionId != -1) { mInstaller.setPermissionsResult(mSessionId, false); } mInstallFlowAnalytics.setFlowFinished( InstallFlowAnalytics.RESULT_CANCELLED_BY_USER); finish(); } } }参考使用Intent安装APK方法(兼容Android N)
平台RK3288 + Android 7.1切入点在点击近期任务后, 长按任务会出现如下界面, 拖动任务到指定区域可以进入分屏模式(DOCK):主窗体 com.android.systemui/.recents.RecentsActivity布局 frameworks/base/packages/SystemUI/res/layout/recents.xml核心View控件RecentView|-- frameworks/base/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java触摸处理|-- frameworks/base/packages/SystemUI/src/com/android/systemui/recents/views/RecentsViewTouchHandler.java长按任务后显示的字符|-- frameworks/base/packages/SystemUI/res/values/strings.xml<string name="recents_drag_hint_message" msgid="2649739267073203985">"在此处拖动即可使用分屏功能"</string>字符使用|-- frameworks/base/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.javaDockState(int dockSide, int createMode, int dockAreaAlpha, int hintTextAlpha, @TextOrientation int hintTextOrientation, RectF touchArea, RectF dockArea, RectF expandedTouchDockArea) { this.dockSide = dockSide; this.createMode = createMode; this.viewState = new ViewState(dockAreaAlpha, hintTextAlpha, hintTextOrientation, R.string.recents_drag_hint_message); this.dockArea = dockArea; this.touchArea = touchArea; this.expandedTouchDockArea = expandedTouchDockArea; }应用列表|-- frameworks/base/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java//长按后的放大率 static final float DRAG_SCALE_FACTOR = 1.05f; //开始拖动 public final void onBusEvent(DragStartEvent event) { // Ensure that the drag task is not animated addIgnoreTask(event.task); if (event.task.isFreeformTask()) { // Animate to the front of the stack mStackScroller.animateScroll(mLayoutAlgorithm.mInitialScrollP, null); } // Enlarge the dragged view slightly float finalScale = event.taskView.getScaleX() * DRAG_SCALE_FACTOR; mLayoutAlgorithm.getStackTransform(event.task, getScroller().getStackScroll(), mTmpTransform, null); mTmpTransform.scale = finalScale; mTmpTransform.translationZ = mLayoutAlgorithm.mMaxTranslationZ + 1; mTmpTransform.dimAlpha = 0f; updateTaskViewToTransform(event.taskView, mTmpTransform, new AnimationProps(DRAG_SCALE_DURATION, Interpolators.FAST_OUT_SLOW_IN)); }应用列表触摸事件, 如滑动, 本章中并非关键作用|-- frameworks/base/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java任务项长按处理, 开始任务的拖拽|-- frameworks/base/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java@Override public boolean onLongClick(View v) { SystemServicesProxy ssp = Recents.getSystemServices(); boolean inBounds = false; Rect clipBounds = new Rect(mViewBounds.mClipBounds); if (!clipBounds.isEmpty()) { // If we are clipping the view to the bounds, manually do the hit test. clipBounds.scale(getScaleX()); inBounds = clipBounds.contains(mDownTouchPos.x, mDownTouchPos.y); } else { // Otherwise just make sure we're within the view's bounds. inBounds = mDownTouchPos.x <= getWidth() && mDownTouchPos.y <= getHeight(); } if (v == this && inBounds && !ssp.hasDockedTask()) { // Start listening for drag events setClipViewInStack(false); mDownTouchPos.x += ((1f - getScaleX()) * getWidth()) / 2; mDownTouchPos.y += ((1f - getScaleY()) * getHeight()) / 2; EventBus.getDefault().register(this, RecentsActivity.EVENT_BUS_PRIORITY + 1); //发送开始拖动事件到EventBus, TaskStackView接收到后, 会放大TaskView EventBus.getDefault().send(new DragStartEvent(mTask, this, mDownTouchPos)); return true; } return false; }RecentView接收并处理DragStartEvent|-- frameworks/base/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.javamTouchHandler = new RecentsViewTouchHandler(this); public final void onBusEvent(DragStartEvent event) { //显示拖放坞(Dock), 见上面的图片 updateVisibleDockRegions(mTouchHandler.getDockStatesForCurrentOrientation(), true /* isDefaultDockState */, TaskStack.DockState.NONE.viewState.dockAreaAlpha, TaskStack.DockState.NONE.viewState.hintTextAlpha, true /* animateAlpha */, false /* animateBounds */); // Temporarily hide the stack action button without changing visibility if (mStackActionButton != null) { mStackActionButton.animate() .alpha(0f) .setDuration(HIDE_STACK_ACTION_BUTTON_DURATION) .setInterpolator(Interpolators.ALPHA_OUT) .start(); } }后续拖动及触摸释放, 若释放前处理有效的分屏区域, 则启动进入分屏模式, 如上图|-- frameworks/base/packages/SystemUI/src/com/android/systemui/recents/views/RecentsViewTouchHandler.javapublic final void onBusEvent(DragStartEvent event) { SystemServicesProxy ssp = Recents.getSystemServices(); //停止父控件拦截输入事件 mRv.getParent().requestDisallowInterceptTouchEvent(true); //后续触摸由此类处理 mDragRequested = true; // We defer starting the actual drag handling until the user moves past the drag slop mIsDragging = false; mDragTask = event.task; mTaskView = event.taskView; mDropTargets.clear(); int[] recentsViewLocation = new int[2]; mRv.getLocationInWindow(recentsViewLocation); mTaskViewOffset.set(mTaskView.getLeft() - recentsViewLocation[0] + event.tlOffset.x, mTaskView.getTop() - recentsViewLocation[1] + event.tlOffset.y); float x = mDownPos.x - mTaskViewOffset.x; float y = mDownPos.y - mTaskViewOffset.y; mTaskView.setTranslationX(x); mTaskView.setTranslationY(y); mVisibleDockStates.clear(); if (ActivityManager.supportsMultiWindow() && !ssp.hasDockedTask() && mDividerSnapAlgorithm.isSplitScreenFeasible()) { Recents.logDockAttempt(mRv.getContext(), event.task.getTopComponent(), event.task.resizeMode); if (!event.task.isDockable) { EventBus.getDefault().send(new ShowIncompatibleAppOverlayEvent()); } else { // Add the dock state drop targets (these take priority) TaskStack.DockState[] dockStates = getDockStatesForCurrentOrientation(); for (TaskStack.DockState dockState : dockStates) { registerDropTargetForCurrentDrag(dockState); dockState.update(mRv.getContext()); mVisibleDockStates.add(dockState); } } } // 初始化了DropTarget, 要切换到分屏, 会先显示放置位置的坞或站点 // Request other drop targets to register themselves EventBus.getDefault().send(new DragStartInitializeDropTargetsEvent(event.task, event.taskView, this)); } private void handleTouchEvent(MotionEvent ev) { int action = ev.getActionMasked(); switch (action) { case MotionEvent.ACTION_DOWN: mDownPos.set((int) ev.getX(), (int) ev.getY()); break; case MotionEvent.ACTION_MOVE: { float evX = ev.getX(); float evY = ev.getY(); float x = evX - mTaskViewOffset.x; float y = evY - mTaskViewOffset.y; if (mDragRequested) { if (!mIsDragging) { mIsDragging = Math.hypot(evX - mDownPos.x, evY - mDownPos.y) > mDragSlop; } if (mIsDragging) { int width = mRv.getMeasuredWidth(); int height = mRv.getMeasuredHeight(); DropTarget currentDropTarget = null; // Give priority to the current drop target to retain the touch handling if (mLastDropTarget != null) { if (mLastDropTarget.acceptsDrop((int) evX, (int) evY, width, height, mRv.mSystemInsets, true /* isCurrentTarget */)) { currentDropTarget = mLastDropTarget; } } // Otherwise, find the next target to handle this event if (currentDropTarget == null) { for (DropTarget target : mDropTargets) { if (target.acceptsDrop((int) evX, (int) evY, width, height, mRv.mSystemInsets, false /* isCurrentTarget */)) { //查找当前的拖放点 currentDropTarget = target; break; } } } if (mLastDropTarget != currentDropTarget) { mLastDropTarget = currentDropTarget; //通知拖放点变化 EventBus.getDefault().send(new DragDropTargetChangedEvent(mDragTask, currentDropTarget)); } } //移动选中的任务 mTaskView.setTranslationX(x); mTaskView.setTranslationY(y); } break; case MotionEvent.ACTION_UP: case MotionEvent.ACTION_CANCEL: { if (mDragRequested) { boolean cancelled = action == MotionEvent.ACTION_CANCEL; if (cancelled) { EventBus.getDefault().send(new DragDropTargetChangedEvent(mDragTask, null)); } //触摸抬起, 发送事件后, 开始切换至分屏模式 EventBus.getDefault().send(new DragEndEvent(mDragTask, mTaskView, !cancelled ? mLastDropTarget : null)); break; } } } }切换至分屏模式|-- frameworks/base/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.javapublic final void onBusEvent(final DragEndEvent event) { // Handle the case where we drop onto a dock region if (event.dropTarget instanceof TaskStack.DockState) { final TaskStack.DockState dockState = (TaskStack.DockState) event.dropTarget; // Hide the dock region updateVisibleDockRegions(null, false /* isDefaultDockState */, -1, -1, false /* animateAlpha */, false /* animateBounds */); // We translated the view but we need to animate it back from the current layout-space // rect to its final layout-space rect Utilities.setViewFrameFromTranslation(event.taskView); // Dock the task and launch it 放置并以新的模式启动 //dockState.createMode的值, 分别对应屏后显示的位置. //import static android.view.WindowManager.DOCKED_BOTTOM; //import static android.view.WindowManager.DOCKED_INVALID; //import static android.view.WindowManager.DOCKED_LEFT; //import static android.view.WindowManager.DOCKED_RIGHT; //import static android.view.WindowManager.DOCKED_TOP; SystemServicesProxy ssp = Recents.getSystemServices(); if (ssp.startTaskInDockedMode(event.task.key.id, dockState.createMode)) { final OnAnimationStartedListener startedListener = new OnAnimationStartedListener() { @Override public void onAnimationStarted() { EventBus.getDefault().send(new DockedFirstAnimationFrameEvent()); // Remove the task and don't bother relaying out, as all the tasks will be // relaid out when the stack changes on the multiwindow change event getStack().removeTask(event.task, null, true /* fromDockGesture */); } }; final Rect taskRect = getTaskRect(event.taskView); IAppTransitionAnimationSpecsFuture future = mTransitionHelper.getAppTransitionFuture( new AnimationSpecComposer() { @Override public List<AppTransitionAnimationSpec> composeSpecs() { return mTransitionHelper.composeDockAnimationSpec( event.taskView, taskRect); } }); ssp.overridePendingAppTransitionMultiThumbFuture(future, mTransitionHelper.wrapStartedListener(startedListener), true /* scaleUp */); MetricsLogger.action(mContext, MetricsEvent.ACTION_WINDOW_DOCK_DRAG_DROP, event.task.getTopComponent().flattenToShortString()); } else { EventBus.getDefault().send(new DragEndCancelledEvent(getStack(), event.task, event.taskView)); } } else { // Animate the overlay alpha back to 0 updateVisibleDockRegions(null, true /* isDefaultDockState */, -1, -1, true /* animateAlpha */, false /* animateBounds */); } // Show the stack action button again without changing visibility if (mStackActionButton != null) { mStackActionButton.animate() .alpha(1f) .setDuration(SHOW_STACK_ACTION_BUTTON_DURATION) .setInterpolator(Interpolators.ALPHA_IN) .start(); } }调用startActivityFromRecents进入应用分屏模式|-- frameworks/base/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java/** Docks a task to the side of the screen and starts it. */ public boolean startTaskInDockedMode(int taskId, int createMode) { if (mIam == null) return false; try { final ActivityOptions options = ActivityOptions.makeBasic(); options.setDockCreateMode(createMode); options.setLaunchStackId(DOCKED_STACK_ID); mIam.startActivityFromRecents(taskId, options.toBundle()); return true; } catch (Exception e) { Log.e(TAG, "Failed to dock task: " + taskId + " with createMode: " + createMode, e); } return false; }与前面另一编文章分析Freeform模式的方式大同小异, 本文中增加了触摸部分代码的整理记录.扩展以指定分屏模式启动指定应用(仅测过DOCK 和 FREEFORM 模式)://import static android.view.WindowManager.DOCKED_BOTTOM; //import static android.view.WindowManager.DOCKED_INVALID; //import static android.view.WindowManager.DOCKED_LEFT; //import static android.view.WindowManager.DOCKED_RIGHT; //import static android.view.WindowManager.DOCKED_TOP; public static final int DOCKED_INVALID = -1; public static final int DOCKED_LEFT = 1; public static final int DOCKED_TOP = 2; public static final int DOCKED_RIGHT = 3; public static final int DOCKED_BOTTOM = 4; //android.app.ActivityManager.StackId.DOCKED_STACK_ID /** Invalid stack ID. */ public static final int INVALID_STACK_ID = -1; /** First static stack ID. */ public static final int FIRST_STATIC_STACK_ID = 0; /** Home activity stack ID. */ public static final int HOME_STACK_ID = FIRST_STATIC_STACK_ID; /** ID of stack where fullscreen activities are normally launched into. */ public static final int FULLSCREEN_WORKSPACE_STACK_ID = 1; /** ID of stack where freeform/resized activities are normally launched into. */ public static final int FREEFORM_WORKSPACE_STACK_ID = FULLSCREEN_WORKSPACE_STACK_ID + 1; /** ID of stack that occupies a dedicated region of the screen. */ public static final int DOCKED_STACK_ID = FREEFORM_WORKSPACE_STACK_ID + 1; /** ID of stack that always on top (always visible) when it exist. */ public static final int PINNED_STACK_ID = DOCKED_STACK_ID + 1; @SuppressLint("NewApi") public static boolean startActivityForMultiScreen(Context context, Intent intent, int stackId, int dockId, Rect bounds){ final ActivityOptions options; if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) { options = ActivityOptions.makeBasic(); Class AOP = ActivityOptions.class; try { //options.setDockCreateMode(createMode); Method setDockCreateMode = AOP.getDeclaredMethod("setDockCreateMode", Integer.TYPE); if(setDockCreateMode != null)setDockCreateMode.invoke(options, dockId); //options.setLaunchStackId(); Method setLaunchStackId = AOP.getDeclaredMethod("setLaunchStackId", Integer.TYPE); if(setLaunchStackId != null)setLaunchStackId.invoke(options, stackId); if(bounds != null && !bounds.isEmpty()){ //need Android N options.setLaunchBounds(bounds.isEmpty() ? null : bounds); } context.startActivity(intent, options.toBundle()); return true; } catch (NoSuchMethodException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } } return false; }Android 7.1 FreeForm 多窗口模式
问题接入某些USB摄像头后, 扬声器没有声音2017-01-01 21:19:24.770 228-287/? E/AudioHardwareTiny: pcm_open(PCM_CARD_HDMI) failed: 222 cannot open device '/dev/snd/pcmC0D1p': No such file or directory原因USB摄像头包含有MIC输入, 在启动初始化后, 会直接抢占card0, 而默认的声卡的初始化比这个慢, 导致card0中, 只有一个有效的输入, 而没有输出;主要的原因还是, 在HAL中, 并没有对无效的输出作处理, 有的, 只有上面一个错误的LOG.解决方案方案一修改USB上电顺序, 延迟初始化到主板声卡后方案二修改HAL, 在打开card0失败后, 尝试打开主板声卡, 可能是card1, card2…参考:diff --git a/hardware/rockchip/audio/tinyalsa_hal/audio_hw.c b/hardware/rockchip/audio/tinyalsa_hal/audio_hw.c index 53069ab..266fcac 100755 --- a/hardware/rockchip/audio/tinyalsa_hal/audio_hw.c +++ b/hardware/rockchip/audio/tinyalsa_hal/audio_hw.c @@ -660,33 +660,54 @@ static int start_output_stream(struct stream_out *out) } } + ALOGD("start_output_stream :666 out->device=%x", out->device); if (out->device & (AUDIO_DEVICE_OUT_SPEAKER | AUDIO_DEVICE_OUT_WIRED_HEADSET | AUDIO_DEVICE_OUT_WIRED_HEADPHONE | AUDIO_DEVICE_OUT_ALL_SCO)) { + int card = PCM_CARD_HDMI; + bool success = true; /* open & close hdmi card to mute hdmi audio */ - out->pcm_device = 1; - out->pcm[PCM_CARD_HDMI] = pcm_open(PCM_CARD_HDMI, out->pcm_device, + out->pcm_device = 1; + ALOGD("start_output_stream pcm_open(%d, %d)", card, out->pcm_device); + out->pcm[0] = pcm_open(card, out->pcm_device, PCM_OUT | PCM_MONOTONIC, &out->config); - if (out->pcm[PCM_CARD_HDMI] && - !pcm_is_ready(out->pcm[PCM_CARD_HDMI])) { - ALOGE("pcm_open(PCM_CARD_HDMI) failed: 222%s", - pcm_get_error(out->pcm[PCM_CARD_HDMI])); - pcm_close(out->pcm[PCM_CARD_HDMI]); - return -ENOMEM; + if (out->pcm[0] && + !pcm_is_ready(out->pcm[0])) { + ALOGE("pcm_open(PCM_CARD_HDMI) failed: 222 %s", + pcm_get_error(out->pcm[0])); + pcm_close(out->pcm[0]); + success = false; + //return -ENOMEM; } - if (out->pcm[PCM_CARD_HDMI]) - pcm_close(out->pcm[PCM_CARD_HDMI]); - out->pcm_device = 0; - out->pcm[PCM_CARD] = pcm_open(PCM_CARD, out->pcm_device, + + if(!success){ + //CARD 1 + card = PCM_CARD_BOARD; + out->pcm[0] = pcm_open(card, out->pcm_device, + PCM_OUT | PCM_MONOTONIC, &out->config); + if (out->pcm[0] && + !pcm_is_ready(out->pcm[0])) { + ALOGE("pcm_open(%d) failed: 222 %s", + card, pcm_get_error(out->pcm[0])); + pcm_close(out->pcm[0]); + return -ENOMEM; + } + } + + if (out->pcm[0]) + pcm_close(out->pcm[0]); + + out->pcm_device = 0; + ALOGD("start_output_stream pcm_open(%d, %d) b", card, out->pcm_device); + out->pcm[0] = pcm_open(card, out->pcm_device, PCM_OUT | PCM_MONOTONIC, &out->config); - if (out->pcm[PCM_CARD] && !pcm_is_ready(out->pcm[PCM_CARD])) { - ALOGE("pcm_open(PCM_CARD) failed: %s", - pcm_get_error(out->pcm[PCM_CARD])); - pcm_close(out->pcm[PCM_CARD]); - return -ENOMEM; + if (out->pcm[0] && !pcm_is_ready(out->pcm[0])) { + ALOGE("pcm_open(PCM_CARD) failed: %s", + pcm_get_error(out->pcm[0])); + pcm_close(out->pcm[0]); + return -ENOMEM; } - } if (out->device & AUDIO_DEVICE_OUT_SPDIF) { @@ -707,8 +728,10 @@ static int start_output_stream(struct stream_out *out) adev->out_device |= out->device; if (out->device & AUDIO_DEVICE_OUT_ALL_SCO) { + ALOGD("start_output_stream ALL_SCO"); start_bt_sco(adev); #ifdef BT_AP_SCO // HARD CODE FIXME + ALOGD("start_output_stream BT_AP_SCO"); out->pcm[PCM_BT] = pcm_open(PCM_BT, 0, PCM_OUT | PCM_MONOTONIC, &pcm_config_ap_sco); ret = create_resampler(48000, @@ -1545,6 +1568,7 @@ static void set_data_slice(void *in_data,struct stream_out *out,size_t length) static ssize_t out_write(struct audio_stream_out *stream, const void* buffer, size_t bytes) { + ALOGD("out_write"); int ret = 0; struct stream_out *out = (struct stream_out *)stream; struct audio_device *adev = out->dev; diff --git a/hardware/rockchip/audio/tinyalsa_hal/audio_hw.h b/hardware/rockchip/audio/tinyalsa_hal/audio_hw.h index aebcd0a..f579c10 100755 --- a/hardware/rockchip/audio/tinyalsa_hal/audio_hw.h +++ b/hardware/rockchip/audio/tinyalsa_hal/audio_hw.h @@ -83,6 +83,7 @@ int PCM_CARD_SPDIF = 1; #else int PCM_CARD = 0; int PCM_CARD_HDMI = 0; +int PCM_CARD_BOARD = 1; int PCM_CARD_SPDIF = 2; #endif int PCM_BT = 3;状态信息//声卡 rk3288:/ # ll proc/asound/ total 0 lrwxrwxrwx 1 root root 5 2017-01-02 00:52 AMCAP -> card0 dr-xr-xr-x 3 root root 0 2017-01-02 00:52 card0 dr-xr-xr-x 5 root root 0 2017-01-02 00:52 card1 -r--r--r-- 1 root root 0 2017-01-02 00:52 cards -r--r--r-- 1 root root 0 2017-01-02 00:52 devices -r--r--r-- 1 root root 0 2017-01-02 00:52 hwdep -r--r--r-- 1 root root 0 2017-01-02 00:52 pcm lrwxrwxrwx 1 root root 5 2017-01-02 00:52 rockchipes8316c -> card1 -r--r--r-- 1 root root 0 2017-01-02 00:52 timers -r--r--r-- 1 root root 0 2017-01-02 00:52 version //声卡信息, 0为USB摄像头 rk3288:/ # cat /proc/asound/cards 0 [AMCAP ]: USB-Audio - USB 2.0 AMCAP Sonix Technology Co., Ltd. USB 2.0 AMCAP at usb-ff540000.usb-1.2, high speed 1 [rockchipes8316c]: rockchip_es8316 - rockchip,es8316-codec rockchip,es8316-codec //声卡设备 rk3288:/ # cat /proc/asound/devices 2: [ 0] : control 3: [ 0- 0]: digital audio capture 4: [ 1] : control 5: [ 1- 0]: digital audio playback 6: [ 1- 0]: digital audio capture 7: [ 1- 1]: digital audio playback 33: : timer //设备节点 rk3288:/dev/snd # ll total 0 crw-rw---- 1 system audio 116, 2 2017-01-02 00:26 controlC0 crw-rw---- 1 system audio 116, 4 2017-01-02 00:26 controlC1 crw-rw---- 1 system audio 116, 3 2017-01-02 00:26 pcmC0D0c crw-rw---- 1 system audio 116, 6 2017-01-02 00:26 pcmC1D0c crw-rw---- 1 system audio 116, 5 2017-01-02 00:26 pcmC1D0p crw-rw---- 1 system audio 116, 7 2017-01-02 00:26 pcmC1D1p crw-rw---- 1 system audio 116, 33 2017-01-02 00:26 timer//输出PCM信息 rk3288:/ # tinypcminfo -D 0 Info for card 0, device 0: PCM out: cannot open device '/dev/snd/pcmC0D0p' Device does not exist. PCM in: Access: 0x000009 Format[0]: 0x000004 Format[1]: 00000000 Format Name: S16_LE Subformat: 0x000001 Rate: min=8000Hz max=48000Hz Channels: min=2 max=2 Sample bits: min=16 max=16 Period size: min=16 max=131072 Period count: min=2 max=1024 rk3288:/ # tinypcminfo -D 1 Info for card 1, device 0: PCM out: Access: 0x000009 Format[0]: 0x000044 Format[1]: 00000000 Format Name: S16_LE, S24_LE Subformat: 0x000001 Rate: min=8000Hz max=96000Hz Channels: min=2 max=2 Sample bits: min=16 max=32 Period size: min=32 max=65536 Period count: min=2 max=4096 PCM in: Access: 0x000009 Format[0]: 0x000044 Format[1]: 00000000 Format Name: S16_LE, S24_LE Subformat: 0x000001 Rate: min=8000Hz max=96000Hz Channels: min=2 max=2 Sample bits: min=16 max=32 Period size: min=32 max=65536 Period count: min=2 max=4096相关源码rk3288_n712$ ll hardware/rockchip/audio/tinyalsa_hal/ alsa_audio.h alsa_mixer.c alsa_route.c amix.c Android.mk asound.h audio_bitstream.c audio_bitstream.h audio_hw.c audio_hw.h audio_hw_hdmi.c audio_hw_hdmi.h audio_setting.c audio_setting.h codec_config/ voice_preprocess.c voice_preprocess.h|-- hardware/rockchip/audio/tinyalsa_hal/audio_hw.cstatic int start_output_stream(struct stream_out *out) { ALOGD("start_output_stream"); char value[PROPERTY_VALUE_MAX] = ""; struct audio_device *adev = out->dev; int type; bool connect_hdmi = true; int ret = 0; ALOGD("%s",__FUNCTION__); if (out == adev->outputs[OUTPUT_HDMI_MULTI]) { force_non_hdmi_out_standby(adev); } else if (adev->outputs[OUTPUT_HDMI_MULTI] && !adev->outputs[OUTPUT_HDMI_MULTI]->standby) { out->disabled = true; return 0; } out->disabled = false; read_hdmi_audioinfo(); int device = getOutputDevice(); ALOGD("start_output_stream device=%x", device); ALOGD("start_output_stream out->device=%x", out->device); if (device == SPDIF_PASSTHROUGH_MODE) { out->device &= ~AUDIO_DEVICE_OUT_AUX_DIGITAL; out->device |= AUDIO_DEVICE_OUT_SPDIF; } else if (device == HDMI_BITSTREAM_MODE) { out->device &= ~AUDIO_DEVICE_OUT_SPDIF; out->device |= AUDIO_DEVICE_OUT_AUX_DIGITAL; } #ifdef BOX_HAL if (out->device & AUDIO_DEVICE_OUT_AUX_DIGITAL) { /*BOX hdmi & codec use the same i2s,so only config the codec card*/ out->device &= ~AUDIO_DEVICE_OUT_SPEAKER; } read_snd_card_info(); if (out->config.flag == HW_PARAMS_FLAG_LPCM){ if(hasSpdif() && ((out->device & AUDIO_DEVICE_OUT_SPDIF)==0)){ out->device |= AUDIO_DEVICE_OUT_SPDIF; } } #ifdef RK3228 if (out->config.flag == HW_PARAMS_FLAG_LPCM) { if (out->device & AUDIO_DEVICE_OUT_AUX_DIGITAL) { out->device |= AUDIO_DEVICE_OUT_SPEAKER; } } #endif out_dump(out, 0); #endif connect_hdmi = true; route_pcm_open(getRouteFromDevice(out->device)); if (out->device & AUDIO_DEVICE_OUT_AUX_DIGITAL) { if (connect_hdmi) { #ifdef BOX_HAL #ifdef USE_DRM int ret = 0; ret = mixer_mode_set(out); if (ret!=0) { ALOGE("mixer mode set error,ret=%d!",ret); } #endif #endif out->pcm_device = 1; out->pcm[PCM_CARD_HDMI] = pcm_open(PCM_CARD_HDMI, out->pcm_device, PCM_OUT | PCM_MONOTONIC, &out->config); if (out->pcm[PCM_CARD_HDMI] && !pcm_is_ready(out->pcm[PCM_CARD_HDMI])) { ALOGE("pcm_open(PCM_CARD_HDMI) failed:111 %s", pcm_get_error(out->pcm[PCM_CARD_HDMI])); pcm_close(out->pcm[PCM_CARD_HDMI]); return -ENOMEM; } } else { ALOGD("The current HDMI is DVI mode"); out->device |= AUDIO_DEVICE_OUT_SPEAKER; } } if (out->device & (AUDIO_DEVICE_OUT_SPEAKER | AUDIO_DEVICE_OUT_WIRED_HEADSET | AUDIO_DEVICE_OUT_WIRED_HEADPHONE | AUDIO_DEVICE_OUT_ALL_SCO)) { /* open & close hdmi card to mute hdmi audio */ out->pcm_device = 1; out->pcm[PCM_CARD_HDMI] = pcm_open(PCM_CARD_HDMI, out->pcm_device, PCM_OUT | PCM_MONOTONIC, &out->config); if (out->pcm[PCM_CARD_HDMI] && !pcm_is_ready(out->pcm[PCM_CARD_HDMI])) { ALOGE("pcm_open(PCM_CARD_HDMI) failed: 222 %s", pcm_get_error(out->pcm[PCM_CARD_HDMI])); pcm_close(out->pcm[PCM_CARD_HDMI]); return -ENOMEM; } if (out->pcm[PCM_CARD_HDMI]) pcm_close(out->pcm[PCM_CARD_HDMI]); out->pcm_device = 0; out->pcm[PCM_CARD] = pcm_open(PCM_CARD, out->pcm_device, PCM_OUT | PCM_MONOTONIC, &out->config); if (out->pcm[PCM_CARD] && !pcm_is_ready(out->pcm[PCM_CARD])) { ALOGE("pcm_open(PCM_CARD) failed: %s", pcm_get_error(out->pcm[PCM_CARD])); pcm_close(out->pcm[PCM_CARD]); return -ENOMEM; } } if (out->device & AUDIO_DEVICE_OUT_SPDIF) { out->pcm_device = 0; out->pcm[PCM_CARD_SPDIF] = pcm_open(PCM_CARD_SPDIF, out->pcm_device, PCM_OUT | PCM_MONOTONIC, &out->config); if (out->pcm[PCM_CARD_SPDIF] && !pcm_is_ready(out->pcm[PCM_CARD_SPDIF])) { ALOGE("pcm_open(PCM_CARD_SPDIF) failed: %s", pcm_get_error(out->pcm[PCM_CARD_SPDIF])); pcm_close(out->pcm[PCM_CARD_SPDIF]); return -ENOMEM; } } adev->out_device |= out->device; if (out->device & AUDIO_DEVICE_OUT_ALL_SCO) { start_bt_sco(adev); #ifdef BT_AP_SCO // HARD CODE FIXME out->pcm[PCM_BT] = pcm_open(PCM_BT, 0, PCM_OUT | PCM_MONOTONIC, &pcm_config_ap_sco); ret = create_resampler(48000, 8000, 2, RESAMPLER_QUALITY_DEFAULT, NULL, &out->resampler); if (ret != 0) { ret = -EINVAL; } #endif } if(adev->hdmiin_state){ ALOGD("%s HDMIin state open hdmiin route",__FUNCTION__); route_pcm_open(HDMI_IN_NORMAL_ROUTE); } return 0; }|-- external/tinyalsa/pcm.c(PCM结构体)struct pcm { int fd; unsigned int flags; int running:1; int prepared:1; int underruns; unsigned int buffer_size; unsigned int boundary; char error[PCM_ERROR_MAX]; struct pcm_config config; struct snd_pcm_mmap_status *mmap_status; struct snd_pcm_mmap_control *mmap_control; struct snd_pcm_sync_ptr *sync_ptr; void *mmap_buffer; unsigned int noirq_frames_per_msec; int wait_for_avail_min; }; struct pcm *pcm_open(unsigned int card, unsigned int device, unsigned int flags, struct pcm_config *config) { struct pcm *pcm; struct snd_pcm_info info; struct snd_pcm_hw_params params; struct snd_pcm_sw_params sparams; char fn[256]; int rc; pcm = calloc(1, sizeof(struct pcm)); if (!pcm || !config) return &bad_pcm; /* TODO: could support default config here */ pcm->config = *config; snprintf(fn, sizeof(fn), "/dev/snd/pcmC%uD%u%c", card, device, flags & PCM_IN ? 'c' : 'p'); pcm->flags = flags; pcm->fd = open(fn, O_RDWR|O_NONBLOCK); if (pcm->fd < 0) { oops(pcm, errno, "cannot open device '%s'", fn); return pcm; } if (fcntl(pcm->fd, F_SETFL, fcntl(pcm->fd, F_GETFL) & ~O_NONBLOCK) < 0) { oops(pcm, errno, "failed to reset blocking mode '%s'", fn); goto fail_close; } if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_INFO, &info)) { oops(pcm, errno, "cannot get info"); goto fail_close; } param_init(&params); param_set_mask(&params, SNDRV_PCM_HW_PARAM_FORMAT, pcm_format_to_alsa(config->format)); param_set_mask(&params, SNDRV_PCM_HW_PARAM_SUBFORMAT, SNDRV_PCM_SUBFORMAT_STD); param_set_min(&params, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, config->period_size); param_set_int(&params, SNDRV_PCM_HW_PARAM_SAMPLE_BITS, pcm_format_to_bits(config->format)); param_set_int(&params, SNDRV_PCM_HW_PARAM_FRAME_BITS, pcm_format_to_bits(config->format) * config->channels); param_set_int(&params, SNDRV_PCM_HW_PARAM_CHANNELS, config->channels); param_set_int(&params, SNDRV_PCM_HW_PARAM_PERIODS, config->period_count); param_set_int(&params, SNDRV_PCM_HW_PARAM_RATE, config->rate); param_set_flag(&params, config->flag); if (flags & PCM_NOIRQ) { if (!(flags & PCM_MMAP)) { oops(pcm, -EINVAL, "noirq only currently supported with mmap()."); goto fail_close; } params.flags |= SNDRV_PCM_HW_PARAMS_NO_PERIOD_WAKEUP; pcm->noirq_frames_per_msec = config->rate / 1000; } if (flags & PCM_MMAP) param_set_mask(&params, SNDRV_PCM_HW_PARAM_ACCESS, SNDRV_PCM_ACCESS_MMAP_INTERLEAVED); else param_set_mask(&params, SNDRV_PCM_HW_PARAM_ACCESS, SNDRV_PCM_ACCESS_RW_INTERLEAVED); if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_HW_PARAMS, &params)) { oops(pcm, errno, "cannot set hw params"); goto fail_close; } /* get our refined hw_params */ config->period_size = param_get_int(&params, SNDRV_PCM_HW_PARAM_PERIOD_SIZE); config->period_count = param_get_int(&params, SNDRV_PCM_HW_PARAM_PERIODS); pcm->buffer_size = config->period_count * config->period_size; if (flags & PCM_MMAP) { pcm->mmap_buffer = mmap(NULL, pcm_frames_to_bytes(pcm, pcm->buffer_size), PROT_READ | PROT_WRITE, MAP_FILE | MAP_SHARED, pcm->fd, 0); if (pcm->mmap_buffer == MAP_FAILED) { oops(pcm, -errno, "failed to mmap buffer %d bytes\n", pcm_frames_to_bytes(pcm, pcm->buffer_size)); goto fail_close; } } memset(&sparams, 0, sizeof(sparams)); sparams.tstamp_mode = SNDRV_PCM_TSTAMP_ENABLE; sparams.period_step = 1; if (!config->start_threshold) { if (pcm->flags & PCM_IN) pcm->config.start_threshold = sparams.start_threshold = 1; else pcm->config.start_threshold = sparams.start_threshold = config->period_count * config->period_size / 2; } else sparams.start_threshold = config->start_threshold; /* pick a high stop threshold - todo: does this need further tuning */ if (!config->stop_threshold) { if (pcm->flags & PCM_IN) pcm->config.stop_threshold = sparams.stop_threshold = config->period_count * config->period_size * 10; else pcm->config.stop_threshold = sparams.stop_threshold = config->period_count * config->period_size; } else sparams.stop_threshold = config->stop_threshold; if (!pcm->config.avail_min) { if (pcm->flags & PCM_MMAP) pcm->config.avail_min = sparams.avail_min = pcm->config.period_size; else pcm->config.avail_min = sparams.avail_min = 1; } else sparams.avail_min = config->avail_min; sparams.xfer_align = config->period_size / 2; /* needed for old kernels */ sparams.silence_threshold = config->silence_threshold; sparams.silence_size = config->silence_size; pcm->boundary = sparams.boundary = pcm->buffer_size; while (pcm->boundary * 2 <= INT_MAX - pcm->buffer_size) pcm->boundary *= 2; if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_SW_PARAMS, &sparams)) { oops(pcm, errno, "cannot set sw params"); goto fail; } rc = pcm_hw_mmap_status(pcm); if (rc < 0) { oops(pcm, rc, "mmap status failed"); goto fail; } #ifdef SNDRV_PCM_IOCTL_TTSTAMP if (pcm->flags & PCM_MONOTONIC) { int arg = SNDRV_PCM_TSTAMP_TYPE_MONOTONIC; rc = ioctl(pcm->fd, SNDRV_PCM_IOCTL_TTSTAMP, &arg); if (rc < 0) { oops(pcm, rc, "cannot set timestamp type"); goto fail; } } #endif pcm->underruns = 0; return pcm; fail: if (flags & PCM_MMAP) munmap(pcm->mmap_buffer, pcm_frames_to_bytes(pcm, pcm->buffer_size)); fail_close: close(pcm->fd); pcm->fd = -1; return pcm; } int pcm_is_ready(struct pcm *pcm) { return pcm->fd >= 0; }资源完整补丁下载
平台RK3288 + Android 9问题官方原文:"从 Android 7.0 开始,系统将阻止应用动态链接非公开 NDK 库,这种库可能会导致您的应用崩溃。此行为变更旨在为跨平台更新和不同设备提供统一的应用体验。即使您的代码可能不会链接私有库,但您的应用中的第三方静态库可能会这么做。因此,所有开发者都应进行相应检查,确保他们的应用不会在运行 Android 7.0 的设备上崩溃。如果您的应用使用原生代码,则只能使用公开 NDK API。"这样会有什么问题?很多使用JNI的APP将无法像低版本SDK一样, 正常使用, 在使用7.1的时候, 系统会有相关的提示, 到使用9.0时, 直接崩溃报错.java.lang.UnsatisfiedLinkError: dlopen failed: library "/system/lib/libserial_port.so" needed or dlopened by "/system/lib/libnativeloader.so" is not accessible for the namespace "classloader-namespace" at java.lang.Runtime.loadLibrary0(Runtime.java:1016) at java.lang.System.loadLibrary(System.java:1669)常见:UnsatisfiedLinkError解决方案方案 1修改APP端见下文记录7.0加载so文件失败:java.lang.UnsatisfiedLinkError: dlopen failed: library “libsqlite.so” not found方案 2 修改系统SDK|-- 错误输出部分代码: bionic/linker/linker.cppstatic bool load_library(android_namespace_t* ns, LoadTask* task, LoadTaskList* load_tasks, int rtld_flags, const std::string& realpath, bool search_linked_namespaces) { off64_t file_offset = task->get_file_offset(); const char* name = task->get_name(); const android_dlextinfo* extinfo = task->get_extinfo(); if ((file_offset % PAGE_SIZE) != 0) { DL_ERR("file offset for the library \"%s\" is not page-aligned: %" PRId64, name, file_offset); return false; } if (file_offset < 0) { DL_ERR("file offset for the library \"%s\" is negative: %" PRId64, name, file_offset); return false; } struct stat file_stat; if (TEMP_FAILURE_RETRY(fstat(task->get_fd(), &file_stat)) != 0) { DL_ERR("unable to stat file for the library \"%s\": %s", name, strerror(errno)); return false; } if (file_offset >= file_stat.st_size) { DL_ERR("file offset for the library \"%s\" >= file size: %" PRId64 " >= %" PRId64, name, file_offset, file_stat.st_size); return false; } // Check for symlink and other situations where // file can have different names, unless ANDROID_DLEXT_FORCE_LOAD is set if (extinfo == nullptr || (extinfo->flags & ANDROID_DLEXT_FORCE_LOAD) == 0) { soinfo* si = nullptr; if (find_loaded_library_by_inode(ns, file_stat, file_offset, search_linked_namespaces, &si)) { TRACE("library \"%s\" is already loaded under different name/path \"%s\" - " "will return existing soinfo", name, si->get_realpath()); task->set_soinfo(si); return true; } } if ((rtld_flags & RTLD_NOLOAD) != 0) { DL_ERR("library \"%s\" wasn't loaded and RTLD_NOLOAD prevented it", name); return false; } struct statfs fs_stat; if (TEMP_FAILURE_RETRY(fstatfs(task->get_fd(), &fs_stat)) != 0) { DL_ERR("unable to fstatfs file for the library \"%s\": %s", name, strerror(errno)); return false; } // do not check accessibility using realpath if fd is located on tmpfs // this enables use of memfd_create() for apps if ((fs_stat.f_type != TMPFS_MAGIC) && (!ns->is_accessible(realpath))) { // TODO(dimitry): workaround for http://b/26394120 - the grey-list // TODO(dimitry) before O release: add a namespace attribute to have this enabled // only for classloader-namespaces const soinfo* needed_by = task->is_dt_needed() ? task->get_needed_by() : nullptr; if (is_greylisted(ns, name, needed_by)) { // print warning only if needed by non-system library if (needed_by == nullptr || !is_system_library(needed_by->get_realpath())) { const soinfo* needed_or_dlopened_by = task->get_needed_by(); const char* sopath = needed_or_dlopened_by == nullptr ? "(unknown)" : needed_or_dlopened_by->get_realpath(); DL_WARN_documented_change(__ANDROID_API_N__, "private-api-enforced-for-api-level-24", "library \"%s\" (\"%s\") needed or dlopened by \"%s\" " "is not accessible by namespace \"%s\"", name, realpath.c_str(), sopath, ns->get_name()); add_dlwarning(sopath, "unauthorized access to", name); } } else { // do not load libraries if they are not accessible for the specified namespace. const char* needed_or_dlopened_by = task->get_needed_by() == nullptr ? "(unknown)" : task->get_needed_by()->get_realpath(); DL_ERR("library \"%s\" needed or dlopened by \"%s\" is not accessible for the namespace \"%s\"", name, needed_or_dlopened_by, ns->get_name()); // do not print this if a library is in the list of shared libraries for linked namespaces if (!maybe_accessible_via_namespace_links(ns, name)) { PRINT("library \"%s\" (\"%s\") needed or dlopened by \"%s\" is not accessible for the" " namespace: [name=\"%s\", ld_library_paths=\"%s\", default_library_paths=\"%s\"," " permitted_paths=\"%s\"]", name, realpath.c_str(), needed_or_dlopened_by, ns->get_name(), android::base::Join(ns->get_ld_library_paths(), ':').c_str(), android::base::Join(ns->get_default_library_paths(), ':').c_str(), android::base::Join(ns->get_permitted_paths(), ':').c_str()); } return false; } } soinfo* si = soinfo_alloc(ns, realpath.c_str(), &file_stat, file_offset, rtld_flags); if (si == nullptr) { return false; } task->set_soinfo(si); // Read the ELF header and some of the segments. if (!task->read(realpath.c_str(), file_stat.st_size)) { soinfo_free(si); task->set_soinfo(nullptr); return false; } // find and set DT_RUNPATH and dt_soname // Note that these field values are temporary and are // going to be overwritten on soinfo::prelink_image // with values from PT_LOAD segments. const ElfReader& elf_reader = task->get_elf_reader(); for (const ElfW(Dyn)* d = elf_reader.dynamic(); d->d_tag != DT_NULL; ++d) { if (d->d_tag == DT_RUNPATH) { si->set_dt_runpath(elf_reader.get_string(d->d_un.d_val)); } if (d->d_tag == DT_SONAME) { si->set_soname(elf_reader.get_string(d->d_un.d_val)); } } for_each_dt_needed(task->get_elf_reader(), [&](const char* name) { load_tasks->push_back(LoadTask::create(name, si, ns, task->get_readers_map())); }); return true; }错误输出:DL_ERR("library \"%s\" needed or dlopened by \"%s\" is not accessible for the namespace \"%s\"", name, needed_or_dlopened_by, ns->get_name());修改的思路是, 不走报错这部分分支的代码, 切入点 is_greylisteddiff --git a/bionic/linker/linker.cpp b/bionic/linker/linker.cpp old mode 100644 new mode 100755 index c78b9ab..0aa83bc --- a/bionic/linker/linker.cpp +++ b/bionic/linker/linker.cpp @@ -200,12 +200,14 @@ static bool is_greylisted(android_namespace_t* ns, const char* name, const soinf "libui.so", "libutils.so", "libvorbisidec.so", + "libserial_port.so", nullptr }; // If you're targeting N, you don't get the greylist. if (g_greylist_disabled || get_application_target_sdk_version() >= __ANDROID_API_N__) { - return false; + //make system lib can be loaded. + //return false; } // if the library needed by a system library - implicitly assume it修改点:将调用的SO加入灰名单列表, 这里加了一个libserial_port.so注释判断SDK和灰名单使能判断的返回, 当然, 也可以强制返回 true, 看需求办事修改后有Warning提示, 忽略:Warning: library "/system/lib/libserial_port.so" ("/system/lib/libserial_port.so") needed or dlopened by "/system/lib/libnativeloader.so" is not accessible by namespace "classloader-namespace" and will not work when the app moves to API level 24 or later (https://android.googlesource.com/platform/bionic/+/master/private-api-enforced-for-api-level-24) (allowing for now because this app's target API level is still 26)已上传资源: linker使用:adb root adb remount adb push linker /system/bin/ adb reboot随着而来的第二个问题:java.lang.UnsatisfiedLinkError: dlopen failed: library "libc++.so" not found at java.lang.Runtime.loadLibrary0(Runtime.java:1016) at java.lang.System.loadLibrary(System.java:1669)|–bionic/linker/linker.cpp@@ -2342,6 +2344,10 @@ android_namespace_t* create_namespace(const void* caller_addr, parse_path(ld_library_path, ":", &ld_library_paths); parse_path(default_library_path, ":", &default_library_paths); + if(strcmp(name, "classloader-namespace") == 0){ + parse_path("/system/lib", ":", &default_library_paths); + } parse_path(permitted_when_isolated_path, ":", &permitted_paths); android_namespace_t* ns = new (g_namespace_allocator.alloc()) android_namespace_t();解决!!完整补丁: linker_patch.tar.gz相关Android 7.0 NDK 行为变更记录7.0加载so文件失败:java.lang.UnsatisfiedLinkError: dlopen failed: library “libsqlite.so” not found
平台RK3288 + Android 7.1需求在高版本的SDK中, 第三方应用申请悬浮窗的权限受到了过一步的限制.除了要在应用中声明对权限的申请:<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>还需要打开设置中的权限:应用可以通过代码检测权限是否已获取:AppOpsManager opsMgr = (AppOpsManager)getSystemService(APP_OPS_SERVICE); int res = opsMgr.checkOp(AppOpsManager.OPSTR_SYSTEM_ALERT_WINDOW, Process.myUid(), getPackageName()); if(res != AppOpsManager.MODE_ALLOWED){ showToast(AppOpsManager.OPSTR_SYSTEM_ALERT_WINDOW + " not allowed"); }有可能会抛出异常:java.lang.SecurityException: com.android.myapp from uid 10066 not allowed to perform SYSTEM_ALERT_WINDOW若需要默认打开, 需要修改相关代码修改frameworks/base/services/core/java/com/android/server/AppOpsService.javaprivate Ops getOpsRawLocked(int uid, String packageName, boolean edit) { //判断是否包含在白名单中, 并将其置为edit 置为 true. //否则, 默认情况下, 则返回空, 导致在应用或其它服务获取packageName时, 发现其并未获取任何操作权限 edit |= checkIfInWhitelist(packageName); UidState uidState = getUidStateLocked(uid, edit); if (uidState == null) { return null; } if (uidState.pkgOps == null) { if (!edit) { return null; } uidState.pkgOps = new ArrayMap<>(); } Ops ops = uidState.pkgOps.get(packageName); if (ops == null) { if (!edit) { return null; } boolean isPrivileged = false; // This is the first time we have seen this package name under this uid, // so let's make sure it is valid. if (uid != 0) { final long ident = Binder.clearCallingIdentity(); try { int pkgUid = -1; try { ApplicationInfo appInfo = ActivityThread.getPackageManager() .getApplicationInfo(packageName, PackageManager.MATCH_DEBUG_TRIAGED_MISSING, UserHandle.getUserId(uid)); if (appInfo != null) { pkgUid = appInfo.uid; isPrivileged = (appInfo.privateFlags & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0; } else { if ("media".equals(packageName)) { pkgUid = Process.MEDIA_UID; isPrivileged = false; } else if ("audioserver".equals(packageName)) { pkgUid = Process.AUDIOSERVER_UID; isPrivileged = false; } else if ("cameraserver".equals(packageName)) { pkgUid = Process.CAMERASERVER_UID; isPrivileged = false; } } } catch (RemoteException e) { Slog.w(TAG, "Could not contact PackageManager", e); } if (pkgUid != uid) { // Oops! The package name is not valid for the uid they are calling // under. Abort. RuntimeException ex = new RuntimeException("here"); ex.fillInStackTrace(); Slog.w(TAG, "Bad call: specified package " + packageName + " under uid " + uid + " but it is really " + pkgUid, ex); return null; } } finally { Binder.restoreCallingIdentity(ident); } } ops = new Ops(packageName, uidState, isPrivileged); if(checkIfInWhitelist(packageName)){ //添加默认权限并设置为允许, 这里只加了SYTEM_ALERT_WINDOW Op op = new Op(ops.uidState.uid, ops.packageName, AppOpsManager.OP_SYSTEM_ALERT_WINDOW); op.mode = AppOpsManager.MODE_ALLOWED; ops.put(op.op, op); } uidState.pkgOps.put(packageName, ops); } return ops; } //allow special package for some permission //把需要添加默认权限的应用包名加入到白名单中. private boolean checkIfInWhitelist(String pkg){ if("com.android.testapp".equals(pkg)){ return true; } //....更多应用 return false; }相关代码APP安装后, 权限为默认值, 即未变更, 默认值:frameworks/base/core/java/android/app/AppOpsManager.javapublic static final int OP_NONE = -1; //.......... /** @hide */ public static final int OP_WRITE_SETTINGS = 23; /** @hide */ public static final int OP_SYSTEM_ALERT_WINDOW = 24; /** * This specifies the default mode for each operation. */ private static int[] sOpDefaultMode = new int[] { AppOpsManager.MODE_ALLOWED, AppOpsManager.MODE_ALLOWED, AppOpsManager.MODE_ALLOWED, AppOpsManager.MODE_ALLOWED, AppOpsManager.MODE_ALLOWED, AppOpsManager.MODE_ALLOWED, AppOpsManager.MODE_ALLOWED, AppOpsManager.MODE_ALLOWED, AppOpsManager.MODE_ALLOWED, AppOpsManager.MODE_ALLOWED, AppOpsManager.MODE_ALLOWED, AppOpsManager.MODE_ALLOWED, AppOpsManager.MODE_ALLOWED, AppOpsManager.MODE_ALLOWED, AppOpsManager.MODE_ALLOWED, AppOpsManager.MODE_IGNORED, // OP_WRITE_SMS AppOpsManager.MODE_ALLOWED, AppOpsManager.MODE_ALLOWED, AppOpsManager.MODE_ALLOWED, AppOpsManager.MODE_ALLOWED, AppOpsManager.MODE_ALLOWED, AppOpsManager.MODE_ALLOWED, AppOpsManager.MODE_ALLOWED, AppOpsManager.MODE_DEFAULT, // OP_WRITE_SETTINGS AppOpsManager.MODE_DEFAULT, // OP_SYSTEM_ALERT_WINDOW AppOpsManager.MODE_ALLOWED, AppOpsManager.MODE_ALLOWED, AppOpsManager.MODE_ALLOWED, AppOpsManager.MODE_ALLOWED, AppOpsManager.MODE_ALLOWED, AppOpsManager.MODE_ALLOWED, AppOpsManager.MODE_ALLOWED, AppOpsManager.MODE_ALLOWED, AppOpsManager.MODE_ALLOWED, AppOpsManager.MODE_ALLOWED, AppOpsManager.MODE_ALLOWED, AppOpsManager.MODE_ALLOWED, AppOpsManager.MODE_ALLOWED, AppOpsManager.MODE_ALLOWED, AppOpsManager.MODE_ALLOWED, AppOpsManager.MODE_ALLOWED, AppOpsManager.MODE_ALLOWED, AppOpsManager.MODE_ALLOWED, AppOpsManager.MODE_DEFAULT, // OP_GET_USAGE_STATS AppOpsManager.MODE_ALLOWED, AppOpsManager.MODE_ALLOWED, AppOpsManager.MODE_IGNORED, // OP_PROJECT_MEDIA AppOpsManager.MODE_IGNORED, // OP_ACTIVATE_VPN AppOpsManager.MODE_ALLOWED, AppOpsManager.MODE_ALLOWED, AppOpsManager.MODE_ALLOWED, AppOpsManager.MODE_ALLOWED, AppOpsManager.MODE_ALLOWED, AppOpsManager.MODE_ALLOWED, AppOpsManager.MODE_ALLOWED, AppOpsManager.MODE_ALLOWED, AppOpsManager.MODE_ALLOWED, AppOpsManager.MODE_ALLOWED, AppOpsManager.MODE_ERRORED, // OP_MOCK_LOCATION AppOpsManager.MODE_ALLOWED, AppOpsManager.MODE_ALLOWED, AppOpsManager.MODE_ALLOWED, // OP_TURN_ON_SCREEN AppOpsManager.MODE_ALLOWED, AppOpsManager.MODE_ALLOWED, // OP_RUN_IN_BACKGROUND };AppOpsManager.MODE_DEFAULT, // OP_SYSTEM_ALERT_WINDOW设置中获取应用的权限packages/apps/Settings/src/com/android/settings/applications/AppStateAppOpsBridge.javapublic PermissionState getPermissionInfo(String pkg, int uid) { PermissionState permissionState = new PermissionState(pkg, new UserHandle(UserHandle .getUserId(uid))); try { permissionState.packageInfo = mIPackageManager.getPackageInfo(pkg, PackageManager.GET_PERMISSIONS | PackageManager.MATCH_UNINSTALLED_PACKAGES, permissionState.userHandle.getIdentifier()); // Check static permission state (whatever that is declared in package manifest) String[] requestedPermissions = permissionState.packageInfo.requestedPermissions; int[] permissionFlags = permissionState.packageInfo.requestedPermissionsFlags; if (requestedPermissions != null) { for (int i = 0; i < requestedPermissions.length; i++) { if (doesAnyPermissionMatch(requestedPermissions[i], mPermissions)) { permissionState.permissionDeclared = true; if ((permissionFlags[i] & PackageInfo.REQUESTED_PERMISSION_GRANTED) != 0) { permissionState.staticPermissionGranted = true; break; } } } } // Check app op state. List<PackageOps> ops = mAppOpsManager.getOpsForPackage(uid, pkg, mAppOpsOpCodes); if (ops != null && ops.size() > 0 && ops.get(0).getOps().size() > 0) { permissionState.appOpMode = ops.get(0).getOps().get(0).getMode(); } } catch (RemoteException e) { Log.w(TAG, "PackageManager is dead. Can't get package info " + pkg, e); } return permissionState; }若未变更设置项, mAppOpsManager.getOpsForPackage将返回空若已变更, 则返回变更后的值Android权限管理与AppOpsManager
平台RK3399 + Android 8.1调试应用: com.android.documentsui问题切换后显示异常, 如下图所示, 窗口明显被拉伸了:正确的显示效果:调试dumpsys window显示异常Window #5 Window{82f86c3 u0 com.android.documentsui/com.android.documentsui.files.FilesActivity}: mDisplayId=0 stackId=2 mSession=Session{8e3c127 1593:u0a10012} mClient=android.os.BinderProxy@4d7d272 mOwnerUid=10012 mShowToOwnerOnly=true package=com.android.documentsui appop=NONE mAttrs=WM.LayoutParams{(0,0)(fillxfill) sim=#10 ty=1 fl=#81810100 pfl=0x20000 fmt=-3 wanim=0x10302f6 vsysui=0x600 surfaceInsets=Rect(40, 40 - 40, 40) (manual) (!preservePreviousSurfaceInsets) needsMenuKey=2 colorMode=0} Requested w=960 h=512 mLayoutSeq=577 mHasSurface=true mShownPosition=[484,90] isReadyForDisplay()=true hasSavedSurface()=false mWindowRemovalAllowed=false WindowStateAnimator{a17f258 com.android.documentsui/com.android.documentsui.files.FilesActivity}: mAnimating=true mLocalAnimating=false mAnimationIsEntrance=false mAnimation=null mStackClip=1 XForm: has=true hasLocal=false {alpha=1.0 matrix=[1.0, 0.0, 0.0][0.0, 1.0, 0.0][0.0, 0.0, 1.0]} Surface: shown=true layer=21010 alpha=1.0 rect=(444.0,50.0) 1040.0 x 592.0 transform=(0.99166936, 0.0, 1.5310801, 0.0) mGlobalScale=1.0 mDsDx=0.99166936 mDtDx=0.0 mDtDy=0.0 mDsDy=1.5310801 isOnScreen=true isVisible=true正常显示Window #5 Window{82f86c3 u0 com.android.documentsui/com.android.documentsui.files.FilesActivity}: mDisplayId=0 stackId=2 mSession=Session{8e3c127 1593:u0a10012} mClient=android.os.BinderProxy@4d7d272 mOwnerUid=10012 mShowToOwnerOnly=true package=com.android.documentsui appop=NONE mAttrs=WM.LayoutParams{(0,0)(fillxfill) sim=#10 ty=1 fl=#81810100 pfl=0x20000 fmt=-3 wanim=0x10302f6 vsysui=0x600 surfaceInsets=Rect(40, 40 - 40, 40) (manual) (!preservePreviousSurfaceInsets) needsMenuKey=2 colorMode=0} Requested w=960 h=512 mLayoutSeq=595 mHasSurface=true mShownPosition=[480,256] isReadyForDisplay()=true hasSavedSurface()=false mWindowRemovalAllowed=false WindowStateAnimator{a17f258 com.android.documentsui/com.android.documentsui.files.FilesActivity}: Surface: shown=true layer=21010 alpha=1.0 rect=(440.0,216.0) 1040.0 x 592.0 transform=(1.0, 0.0, 1.0, 0.0) isOnScreen=true isVisible=true从近期任务切换为FreeForm模式:com.android.server.am.ActivityManagerService.startActivityFromRecents(ActivityManagerService.java:4935) com.android.server.am.ActivityStackSupervisor.startActivityFromRecentsInner(ActivityStackSupervisor.java:4882) com.android.server.wm.WindowManagerService.continueSurfaceLayout(WindowManagerService.java:2979) com.android.server.wm.WindowSurfacePlacer.continueLayout(WindowSurfacePlacer.java:126) com.android.server.wm.WindowSurfacePlacer.performSurfacePlacement(WindowSurfacePlacer.java:135) com.android.server.wm.WindowSurfacePlacer.performSurfacePlacement(WindowSurfacePlacer.java:145) com.android.server.wm.WindowSurfacePlacer.performSurfacePlacementLoop(WindowSurfacePlacer.java:197) com.android.server.wm.RootWindowContainer.performSurfacePlacement(RootWindowContainer.java:608) com.android.server.wm.RootWindowContainer.applySurfaceChangesTransaction(RootWindowContainer.java:865) com.android.server.wm.DisplayContent.applySurfaceChangesTransaction(DisplayContent.java:2784) com.android.server.wm.WindowContainer.forAllWindows(WindowContainer.java:633) com.android.server.wm.DisplayContent.forAllWindows(DisplayContent.java:1533) com.android.server.wm.WindowContainer.forAllWindows(WindowContainer.java:616) com.android.server.wm.WindowContainer.forAllWindows(WindowContainer.java:616) com.android.server.wm.WindowState.forAllWindows(WindowState.java:4034) com.android.server.wm.WindowState.applyInOrderWithImeWindows(WindowState.java:4127) com.android.server.wm.WindowContainer$ForAllWindowsConsumerWrapper.apply(WindowContainer.java:777) com.android.server.wm.WindowContainer$ForAllWindowsConsumerWrapper.apply(WindowContainer.java:779)AppWindowAnimator.javacom.android.server.wm.RootWindowContainer.performSurfacePlacement(RootWindowContainer.java:623) com.android.server.wm.WindowSurfacePlacer.handleAppTransitionReadyLocked(WindowSurfacePlacer.java:344) com.android.server.wm.WindowSurfacePlacer.handleOpeningApps(WindowSurfacePlacer.java:404) com.android.server.wm.AppWindowToken.setVisibility(AppWindowToken.java:372) com.android.server.wm.WindowManagerService.applyAnimationLocked(WindowManagerService.java:2435) com.android.server.wm.AppWindowAnimator.setAnimation(AppWindowAnimator.java:127)在APP切换动画启动后,WindowStateAnimator中计算并重新设置上面dump出来的相关变量: mShownPosition 和 transform问题的根源在于 startProlongAnimation 调用了, 但 endProlongedAnimation 却迟迟未调用, 导致动画被无限推后, mShownPosition 和 transform 也一直无变化:AppWindowAnimator/** * Sometimes we need to synchronize the first frame of animation with some external event, e.g. * Recents hiding some of its content. To achieve this, we prolong the start of the animaiton * and keep producing the first frame of the animation. */ private long getAnimationFrameTime(Animation animation, long currentTime) { if (mProlongAnimation == PROLONG_ANIMATION_AT_START) { animation.setStartTime(currentTime); return currentTime + 1; } return currentTime; } private boolean stepAnimation(long currentTime) { if (animation == null) { return false; } transformation.clear(); final long animationFrameTime = getAnimationFrameTime(animation, currentTime); ... } void startProlongAnimation(int prolongType) { if(!ffNoCaption)mProlongAnimation = prolongType; mClearProlongedAnimation = false; } void endProlongedAnimation() { mProlongAnimation = PROLONG_ANIMATION_DISABLED; }WindowManagerService.java@Override public void endProlongedAnimations() { synchronized (mWindowMap) { for (final WindowState win : mWindowMap.values()) { final AppWindowToken appToken = win.mAppToken; if (appToken != null && appToken.mAppAnimator != null) { appToken.mAppAnimator.endProlongedAnimation(); } } mAppTransition.notifyProlongedAnimationsEnded(); } }加上调试LOG后输出://开始切换: 05-30 05:13:25.287 D/AppWindowAnimator 497): startProlongAnimation 80261794 05-30 05:13:25.298 D/RecentsActivity( 670): addOnPreDrawListener 2 05-30 05:13:25.301 D/RecentsActivity( 670): onPreDraw //从mWindowMap 中删除 com.android.documentsui 05-30 05:13:25.309 D/WindowManagerService( 497): postWindowRemoveCleanupLocked remove com.android.documentsui/com.android.documentsui.files.FilesActivity 05-30 05:13:25.336 D/RecentsActivity( 670): Recents.getSystemServices().endProlongedAnimations(); //开始遍历并调用 AppWindowAnimator.endProlongedAnimation 05-30 05:13:25.337 D/WindowManagerService( 497): endProlongedAnimations win.mAppToken.stringName=com.android.systemui/com.android.systemui.recents.RecentsActivity 05-30 05:13:25.337 D/AppWindowAnimator( 497): endProlongedAnimation 43221400 05-30 05:13:25.337 D/WindowManagerService( 497): endProlongedAnimations win.mAppToken.stringName=NavigationBar 05-30 05:13:25.337 D/WindowManagerService( 497): endProlongedAnimations win.mAppToken.stringName=NavigationBar mAppAnimator is NULL 05-30 05:13:25.337 D/WindowManagerService( 497): endProlongedAnimations win.mAppToken.stringName=AssistPreviewPanel 05-30 05:13:25.337 D/WindowManagerService( 497): endProlongedAnimations win.mAppToken.stringName=AssistPreviewPanel mAppAnimator is NULL 05-30 05:13:25.337 D/WindowManagerService( 497): endProlongedAnimations win.mAppToken.stringName=DockedStackDivider 05-30 05:13:25.337 D/WindowManagerService( 497): endProlongedAnimations win.mAppToken.stringName=DockedStackDivider mAppAnimator is NULL 05-30 05:13:25.337 D/WindowManagerService( 497): endProlongedAnimations win.mAppToken.stringName=com.android.launcher3/com.android.launcher3.Launcher 05-30 05:13:25.337 D/AppWindowAnimator( 497): endProlongedAnimation 73295989 05-30 05:13:25.337 D/WindowManagerService( 497): endProlongedAnimations win.mAppToken.stringName=StatusBar 05-30 05:13:25.337 D/WindowManagerService( 497): endProlongedAnimations win.mAppToken.stringName=StatusBar mAppAnimator is NULL 05-30 05:13:25.337 D/WindowManagerService( 497): endProlongedAnimations win.mAppToken.stringName=com.android.systemui.ImageWallpaper 05-30 05:13:25.337 D/WindowManagerService( 497): endProlongedAnimations win.mAppToken.stringName=com.android.systemui.ImageWallpaper mAppAnimator is NULL //重新将 com.android.documentsui 加入 mWindowMap 中 05-30 05:13:25.404 D/WindowManagerService( 497): addWindow com.android.documentsui/com.android.documentsui.files.FilesActivity从调试的LOG看, 对应com.android.documentsui的Window在循环调用 AppWindowAnimator.endProlongedAnimation时, 完美地错过了…解决:frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.javapublic int addWindow(Session session, IWindow client, int seq, WindowManager.LayoutParams attrs, int viewVisibility, int displayId, Rect outContentInsets, Rect outStableInsets, Rect outOutsets, InputChannel outInputChannel) { int[] appOp = new int[1]; int res = mPolicy.checkAddPermission(attrs, appOp); //...省略代码... } else if (rootType >= FIRST_APPLICATION_WINDOW && rootType <= LAST_APPLICATION_WINDOW) { atoken = token.asAppWindowToken(); //增加代码 if(atoken != null && atoken.mAppAnimator != null){atoken.mAppAnimator.endProlongedAnimation();} //....省略代码....
平台RK3288 + Android 7.1关于FreeformAndroid N上的多窗口功能有三种模式:(扩展-4)分屏模式这种模式可以在手机上使用。该模式将屏幕一分为二,同时显示两个应用的界面。画中画模式这种模式主要在TV上使用,在该模式下视频播放的窗口可以一直在最顶层显示。Freeform模式这种模式类似于我们常见的桌面操作系统,应用界面的窗口可以自由拖动和修改大小。效果图切入平台默认并没有打开这个模式的支持, 需要增加一个文件以打开Feeeform特性增加 /system/etc/permissions/android.software.freeform_window_management.xml<?xml version="1.0" encoding="utf-8"?> <!-- Copyright (C) 2015 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. --> <permissions> <feature name="android.software.freeform_window_management" /> </permissions>打开后:看任务右上角 X 旁边的图标然而, 当尝试点击此按键后, 预想的画面并没有出现, 费解!排查跟踪下源码中此界面的布局:frameworks/base/packages/SystemUI/res/layout/recents_task_view_header.xml<?xml version="1.0" encoding="utf-8"?> <!-- Copyright (C) 2014 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. --> <!-- The layouts params are calculated in TaskViewHeader.java --> <com.android.systemui.recents.views.TaskViewHeader xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/task_view_bar" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_gravity="top|center_horizontal"> <com.android.systemui.recents.views.FixedSizeImageView android:id="@+id/icon" android:contentDescription="@string/recents_app_info_button_label" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_vertical|start" android:paddingTop="8dp" android:paddingBottom="8dp" android:paddingStart="16dp" android:paddingEnd="12dp" /> <TextView android:id="@+id/title" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_gravity="center_vertical|start" android:textSize="16sp" android:textColor="#ffffffff" android:text="@string/recents_empty_message" android:fontFamily="sans-serif-medium" android:singleLine="true" android:maxLines="1" android:ellipsize="marquee" android:fadingEdge="horizontal" android:forceHasOverlappingRendering="false" /> <com.android.systemui.recents.views.FixedSizeImageView android:id="@+id/move_task" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_vertical|end" android:padding="@dimen/recents_task_view_header_button_padding" android:src="@drawable/star" android:background="?android:selectableItemBackground" android:alpha="0" android:visibility="gone" /> <com.android.systemui.recents.views.FixedSizeImageView android:id="@+id/dismiss_task" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_vertical|end" android:padding="@dimen/recents_task_view_header_button_padding" android:src="@drawable/recents_dismiss_light" android:background="?android:selectableItemBackground" android:alpha="0" android:visibility="gone" /> <!-- The progress indicator shows if auto-paging is enabled --> <ViewStub android:id="@+id/focus_timer_indicator_stub" android:inflatedId="@+id/focus_timer_indicator" android:layout="@layout/recents_task_view_header_progress_bar" android:layout_width="match_parent" android:layout_height="5dp" android:layout_gravity="bottom" /> <!-- The app overlay shows as the user long-presses on the app icon --> <ViewStub android:id="@+id/app_overlay_stub" android:inflatedId="@+id/app_overlay" android:layout="@layout/recents_task_view_header_overlay" android:layout_width="match_parent" android:layout_height="match_parent" /> </com.android.systemui.recents.views.TaskViewHeader>对应的自定义VIEW控件frameworks/base/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java/* The task bar view */ public class TaskViewHeader extends FrameLayout implements View.OnClickListener, View.OnLongClickListener { @Override protected void onFinishInflate() { SystemServicesProxy ssp = Recents.getSystemServices(); // Initialize the icon and description views mIconView = (ImageView) findViewById(R.id.icon); mIconView.setOnLongClickListener(this); mTitleView = (TextView) findViewById(R.id.title); mDismissButton = (ImageView) findViewById(R.id.dismiss_task); if (ssp.hasFreeformWorkspaceSupport()) { mMoveTaskButton = (ImageView) findViewById(R.id.move_task); } onConfigurationChanged(); } @Override public void onClick(View v) { if (v == mIconView) { //... } else if (v == mMoveTaskButton) { TaskView tv = Utilities.findParent(this, TaskView.class); EventBus.getDefault().send(new LaunchTaskEvent(tv, mTask, null, mMoveTaskTargetStackId, false)); } else if (v == mAppInfoView) { //... } } }重点关注点击的实现的事件关于LaunchTaskEventframeworks/base/packages/SystemUI/src/com/android/systemui/recents/events/activity/LaunchTaskEvent.javapublic class LaunchTaskEvent extends EventBus.Event { public final TaskView taskView; public final Task task; public final Rect targetTaskBounds; public final int targetTaskStack; public final boolean screenPinningRequested; public LaunchTaskEvent(TaskView taskView, Task task, Rect targetTaskBounds, int targetTaskStack, boolean screenPinningRequested) { this.taskView = taskView; this.task = task; this.targetTaskBounds = targetTaskBounds; this.targetTaskStack = targetTaskStack; this.screenPinningRequested = screenPinningRequested; } }检测是否支持自由窗口模式frameworks/base/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java/** Private constructor */ private SystemServicesProxy(Context context) { mAccm = AccessibilityManager.getInstance(context); mAm = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE); mIam = ActivityManagerNative.getDefault(); mPm = context.getPackageManager(); mIpm = AppGlobals.getPackageManager(); mAssistUtils = new AssistUtils(context); mWm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); mIwm = WindowManagerGlobal.getWindowManagerService(); mUm = UserManager.get(context); mDisplay = mWm.getDefaultDisplay(); mRecentsPackage = context.getPackageName(); mHasFreeformWorkspaceSupport = mPm.hasSystemFeature(PackageManager.FEATURE_FREEFORM_WINDOW_MANAGEMENT) || Settings.Global.getInt(context.getContentResolver(), DEVELOPMENT_ENABLE_FREEFORM_WINDOWS_SUPPORT, 0) != 0; } /** * Returns whether this device has freeform workspaces. */ public boolean hasFreeformWorkspaceSupport() { return mHasFreeformWorkspaceSupport; }点击后, 加入事件队列frameworks/base/packages/SystemUI/src/com/android/systemui/recents/events/EventBus.java/** * Sends an event to the subscribers of the given event type immediately. This can only be * called from the same thread as the EventBus's looper thread (for the default EventBus, this * is the main application thread). */ public void send(Event event) { // Fail immediately if we are being called from the non-main thread //... queueEvent(event); } /** * Processes and dispatches the given event to the given event handler, on the thread of whoever * calls this method. */ private void processEvent(final EventHandler eventHandler, final Event event) { //...反射调用. eventHandler.method.invoke(sub, event); //... }eventHandler的由来:frameworks/base/packages/SystemUI/src/com/android/systemui/recents/events/EventBus.javaprivate static final String METHOD_PREFIX = "onBusEvent"; public void register(Object subscriber) { registerSubscriber(subscriber, DEFAULT_SUBSCRIBER_PRIORITY, null); } public void register(Object subscriber, int priority) { registerSubscriber(subscriber, priority, null); } /** * Registers a new subscriber. */ private void registerSubscriber(Object subscriber, int priority, MutableBoolean hasInterprocessEventsChangedOut) { //... // Find all the valid event bus handler methods of the subscriber MutableBoolean isInterprocessEvent = new MutableBoolean(false); Method[] methods = subscriberType.getDeclaredMethods(); for (Method m : methods) { Class<?>[] parameterTypes = m.getParameterTypes(); isInterprocessEvent.value = false; if (isValidEventBusHandlerMethod(m, parameterTypes, isInterprocessEvent)) { Class<? extends Event> eventType = (Class<? extends Event>) parameterTypes[0]; ArrayList<EventHandler> eventTypeHandlers = mEventTypeMap.get(eventType); if (eventTypeHandlers == null) { eventTypeHandlers = new ArrayList<>(); mEventTypeMap.put(eventType, eventTypeHandlers); } if (isInterprocessEvent.value) { try { // Enforce that the event must have a Bundle constructor eventType.getConstructor(Bundle.class); mInterprocessEventNameMap.put(eventType.getName(), (Class<? extends InterprocessEvent>) eventType); if (hasInterprocessEventsChangedOut != null) { hasInterprocessEventsChangedOut.value = true; } } catch (NoSuchMethodException e) { throw new RuntimeException("Expected InterprocessEvent to have a Bundle constructor"); } } EventHandlerMethod method = new EventHandlerMethod(m, eventType); EventHandler handler = new EventHandler(sub, method, priority); eventTypeHandlers.add(handler); //保存函数 subscriberMethods.add(method); sortEventHandlersByPriority(eventTypeHandlers); if (DEBUG_TRACE_ALL) { logWithPid(" * Method: " + m.getName() + " event: " + parameterTypes[0].getSimpleName() + " interprocess? " + isInterprocessEvent.value); } } } //... } //检测对应的方法 /** * @return whether {@param method} is a valid (normal or interprocess) event bus handler method */ private boolean isValidEventBusHandlerMethod(Method method, Class<?>[] parameterTypes, MutableBoolean isInterprocessEventOut) { int modifiers = method.getModifiers(); if (Modifier.isPublic(modifiers) && Modifier.isFinal(modifiers) && method.getReturnType().equals(Void.TYPE) && parameterTypes.length == 1) { if (EventBus.InterprocessEvent.class.isAssignableFrom(parameterTypes[0]) && method.getName().startsWith(INTERPROCESS_METHOD_PREFIX)) { isInterprocessEventOut.value = true; return true; } else if (EventBus.Event.class.isAssignableFrom(parameterTypes[0]) && method.getName().startsWith(METHOD_PREFIX)) { isInterprocessEventOut.value = false; return true; } else { if (DEBUG_TRACE_ALL) { if (!EventBus.Event.class.isAssignableFrom(parameterTypes[0])) { logWithPid(" Expected method take an Event-based parameter: " + method.getName()); } else if (!method.getName().startsWith(INTERPROCESS_METHOD_PREFIX) && !method.getName().startsWith(METHOD_PREFIX)) { logWithPid(" Expected method start with method prefix: " + method.getName()); } } } } else { if (DEBUG_TRACE_ALL) { if (!Modifier.isPublic(modifiers)) { logWithPid(" Expected method to be public: " + method.getName()); } else if (!Modifier.isFinal(modifiers)) { logWithPid(" Expected method to be final: " + method.getName()); } else if (!method.getReturnType().equals(Void.TYPE)) { logWithPid(" Expected method to return null: " + method.getName()); } } } return false; }处理事件, 开始执行切换frameworks/base/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.javapublic final void onBusEvent(LaunchTaskEvent event) { mLastTaskLaunchedWasFreeform = event.task.isFreeformTask(); mTransitionHelper.launchTaskFromRecents(getStack(), event.task, mTaskStackView, event.taskView, event.screenPinningRequested, event.targetTaskBounds, event.targetTaskStack); }frameworks/base/packages/SystemUI/src/com/android/systemui/recents/views/RecentsTransitionHelper.java/** * Launches the specified {@link Task}. */ public void launchTaskFromRecents(final TaskStack stack, @Nullable final Task task, final TaskStackView stackView, final TaskView taskView, final boolean screenPinningRequested, final Rect bounds, final int destinationStack) { final ActivityOptions opts = ActivityOptions.makeBasic(); if (bounds != null) { opts.setLaunchBounds(bounds.isEmpty() ? null : bounds); } //... if (taskView == null) { // If there is no task view, then we do not need to worry about animating out occluding // task views, and we can launch immediately startTaskActivity(stack, task, taskView, opts, transitionFuture, animStartedListener); } else { LaunchTaskStartedEvent launchStartedEvent = new LaunchTaskStartedEvent(taskView, screenPinningRequested); if (task.group != null && !task.group.isFrontMostTask(task)) { launchStartedEvent.addPostAnimationCallback(new Runnable() { @Override public void run() { startTaskActivity(stack, task, taskView, opts, transitionFuture, animStartedListener); } }); EventBus.getDefault().send(launchStartedEvent); } else { EventBus.getDefault().send(launchStartedEvent); startTaskActivity(stack, task, taskView, opts, transitionFuture, animStartedListener); } } Recents.getSystemServices().sendCloseSystemWindows( BaseStatusBar.SYSTEM_DIALOG_REASON_HOME_KEY); } /** * Starts the activity for the launch task. * * @param taskView this is the {@link TaskView} that we are launching from. This can be null if * we are toggling recents and the launch-to task is now offscreen. */ private void startTaskActivity(TaskStack stack, Task task, @Nullable TaskView taskView, ActivityOptions opts, IAppTransitionAnimationSpecsFuture transitionFuture, final ActivityOptions.OnAnimationStartedListener animStartedListener) { SystemServicesProxy ssp = Recents.getSystemServices(); if (ssp.startActivityFromRecents(mContext, task.key, task.title, opts)) { // Keep track of the index of the task launch int taskIndexFromFront = 0; int taskIndex = stack.indexOfStackTask(task); if (taskIndex > -1) { taskIndexFromFront = stack.getTaskCount() - taskIndex - 1; } EventBus.getDefault().send(new LaunchTaskSucceededEvent(taskIndexFromFront)); } else { // Dismiss the task if we fail to launch it if (taskView != null) { taskView.dismissTask(); } // Keep track of failed launches EventBus.getDefault().send(new LaunchTaskFailedEvent()); } if (transitionFuture != null) { ssp.overridePendingAppTransitionMultiThumbFuture(transitionFuture, wrapStartedListener(animStartedListener), true /* scaleUp */); } }frameworks/base/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java/** Starts an activity from recents. */ public boolean startActivityFromRecents(Context context, Task.TaskKey taskKey, String taskName, ActivityOptions options) { if (mIam != null) { try { if (taskKey.stackId == DOCKED_STACK_ID) { // We show non-visible docked tasks in Recents, but we always want to launch // them in the fullscreen stack. if (options == null) { options = ActivityOptions.makeBasic(); } options.setLaunchStackId(FULLSCREEN_WORKSPACE_STACK_ID); } mIam.startActivityFromRecents( taskKey.id, options == null ? null : options.toBundle()); return true; } catch (Exception e) { Log.e(TAG, context.getString(R.string.recents_launch_error_message, taskName), e); } } return false; }进入ActivityManagerService并切换frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.javapublic final int startActivityFromRecents(int taskId, Bundle bOptions)frameworks/base/services/core/java/com/android/server/am/ActivityStackSupervisor.javafinal int startActivityFromRecentsInner(int taskId, Bundle bOptions)解决原因: 在 RecentsTransitionHelper.java中, 打开任务的参数缺少了ActivityOptions.setLaunchStackId的设置://frameworks/base/packages/SystemUI/src/com/android/systemui/recents/views/RecentsTransitionHelper.java public void launchTaskFromRecents(final TaskStack stack, @Nullable final Task task, final TaskStackView stackView, final TaskView taskView, final boolean screenPinningRequested, final Rect bounds, final int destinationStack) { final ActivityOptions opts = ActivityOptions.makeBasic(); //----新增代码---- opts.setLaunchStackId(destinationStack); if (bounds != null) { opts.setLaunchBounds(bounds.isEmpty() ? null : bounds); } //... }编译并更新SystemUI, 完成!扩展Android Freeform模式 关键最后一步How to Enable Freeform Multi-Window Mode in Android NougatAndroid 7.0中的多窗口实现解析Android N 多窗口功能初探几个关键变量://frameworks/base/core/java/android/app/ActivityManager.java /** Home activity stack ID. */ public static final int HOME_STACK_ID = FIRST_STATIC_STACK_ID; /** ID of stack where fullscreen activities are normally launched into. */ public static final int FULLSCREEN_WORKSPACE_STACK_ID = 1; /** ID of stack where freeform/resized activities are normally launched into. */ public static final int FREEFORM_WORKSPACE_STACK_ID = FULLSCREEN_WORKSPACE_STACK_ID + 1; /** ID of stack that occupies a dedicated region of the screen. */ public static final int DOCKED_STACK_ID = FREEFORM_WORKSPACE_STACK_ID + 1; /** ID of stack that always on top (always visible) when it exist. */ public static final int PINNED_STACK_ID = DOCKED_STACK_ID + 1;
前言Android的摄像头的功能扩展越来越丰富, 近段时间因为涉及到RTSP推送的需求, 稍微了解记录踩过的坑.服务端纯JAVA开发的服务端项目, 几年前用过, 时至今日, 依然好用.spydroid-ipcamera使用高阶说明如: 使用音频和视频->rtsp://xxx.xxx.xxx.xxx:8086?aac&h264客户端客户端, PC上建议用VLC, 在调试很方便, 功能也强大.手机端, 这个重点说说, 毕竟, 在几年前, 踩过较深的坑就是它:Awesome Open Source 从这里找到开源的项目然后, 尝试后的结果是:SmarterStreaming [x] 太大了, 下不下来, 没耐心…EasyPlayer-RTSP-Android [v] 需要申请APPID, 国内开源SDK的套路EasyPlayer-RTSP-Android-APK [v] 需要申请APPID, 国内开源SDK的套路RTSP.Player.Android [v] 最终采用这个, 效果也不错, 但兼容性没测过.延迟这是个老生常谈的问题手机端的VideoView/MeidaPlayer控件, 在播放后, 经常会发现有5秒的延迟在PC上使用VLC测试, 默认设置的情况下, 会在2秒左右最开始, 怀疑是服务端的问题, 折腾了不少时间, 只能说, 还是太年轻了VLC中连接的设置:缓存适当降低, 如, 把1000ms 改为200ms手机端, 就要找到好用的播放控件或工具RTSPPlayer: 这个项目, 曾经效果还不错, 只是最近测试发现, 经常连不上或连上后没图像或花屏, 接口中, 延时可以支持100ms左右.vlc-android: 怎么说呢, 强大, 但要很能折腾, 曾经下载并编译过, 最终出来的效果却不尽如人意(跟官方发布的APK表现不同)扩展图像格式转换Android YUV图像转换算法和检测工具YUV420P、YUV420SP、NV12、NV21和RGB互相转换并存储为JPEG以及PNG图片GIT clone失败$ git clone https://github.com/tsingsee/EasyPlayer-RTSP-Android.git 正克隆到 'EasyPlayer-RTSP-Android'... remote: Enumerating objects: 50, done. remote: Counting objects: 100% (50/50), done. remote: Compressing objects: 100% (29/29), done. error: RPC failed; curl 18 transfer closed with outstanding read data remaining fatal: The remote end hung up unexpectedly fatal: 过早的文件结束符(EOF) fatal: index-pack failedgit clone时RPC failed; curl 18 transfer closed with outstanding read data remaining
平台RK3288 + Android 7.1开发在开始之前需要先了解下当前的音频设备情况:查看当前支持的声卡设备(找到card[0, N])rk3288:/proc/asound # ll total 0 lrwxrwxrwx 1 root root 5 2020-04-15 13:51 Camera -> card1 dr-xr-xr-x 5 root root 0 2020-04-15 13:51 card0 dr-xr-xr-x 3 root root 0 2020-04-15 13:51 card1 -r--r--r-- 1 root root 0 2020-04-15 13:51 cards -r--r--r-- 1 root root 0 2020-04-15 13:51 devices -r--r--r-- 1 root root 0 2020-04-15 13:51 hwdep -r--r--r-- 1 root root 0 2020-04-15 13:51 pcm lrwxrwxrwx 1 root root 5 2020-04-15 13:51 rockchipes8316c -> card0 -r--r--r-- 1 root root 0 2020-04-15 13:51 timers -r--r--r-- 1 root root 0 2020-04-15 13:51 version查看cards中的内容:rk3288:/proc/asound # cat cards 0 [rockchipes8316c]: rockchip_es8316 - rockchip,es8316-codec rockchip,es8316-codec 1 [Camera ]: USB-Audio - USB Camera Generic USB Camera at usb-ff540000.usb-1.2, high speed当前使用的声卡信息rk3288:/proc/asound # tinypcminfo -D 0 Info for card 0, device 0: PCM out: Access: 0x000009 Format[0]: 0x000044 Format[1]: 00000000 Format Name: S16_LE, S24_LE Subformat: 0x000001 Rate: min=8000Hz max=96000Hz Channels: min=2 max=2 Sample bits: min=16 max=32 Period size: min=32 max=65536 Period count: min=2 max=4096 PCM in: Access: 0x000009 Format[0]: 0x000044 Format[1]: 00000000 Format Name: S16_LE, S24_LE Subformat: 0x000001 Rate: min=8000Hz max=96000Hz Channels: min=2 max=2 Sample bits: min=16 max=32 Period size: min=32 max=65536 Period count: min=2 max=4096采集API:AudioRecord//audioSource: MediaRecorder.AudioSource.CAMCORDER, MediaRecorder.AudioSource.MIC 等 // 一般情况下会用到这两个 //sampleRateInHz: 常用的有: 8000,11025,16000,22050,44100,96000; //channelConfig: AudioFormat.CHANNEL_CONFIGURATION_DEFAULT, 单声道和立声 //audioFormat: AudioFormat.ENCODING_PCM_16BIT, 测试中要捕获PCM数据, 其它参数未研究. //bufferSizeInBytes: 由AudioRecord.getMinBufferSize(sampleRateInHz, channelConfig, audioFormat)获得 public AudioRecord(int audioSource, int sampleRateInHz, int channelConfig, int audioFormat, int bufferSizeInBytes)播放API: AudioTrack//streamType: AudioManager.STREAM_MUSIC, 输出通道, 也可以选择ALARM等 //sampleRateInHz: 常用的有: 8000,11025,16000,22050,44100,96000; //channelConfig: AudioFormat.CHANNEL_CONFIGURATION_DEFAULT, 单声道和立声 //audioFormat: AudioFormat.ENCODING_PCM_16BIT, 测试中要捕获PCM数据, 其它参数未研究. //bufferSizeInBytes: //mode: AudioTrack中有MODE_STATIC和MODE_STREAM两种分类。 // STREAM的意思是由用户在应用程序通过write方式把数据一次一次得写到audiotrack中。 // 这个和我们在socket中发送数据一样,应用层从某个地方获取数据,例如通过编解码得到PCM数据,然后write到audiotrack。 // 这种方式的坏处就是总是在JAVA层和Native层交互,效率损失较大。 // 而STATIC的意思是一开始创建的时候,就把音频数据放到一个固定的buffer,然后直接传给audiotrack, // 后续就不用一次次得write了。AudioTrack会自己播放这个buffer中的数据。 // 这种方法对于铃声等内存占用较小,延时要求较高的声音来说很适用。 public AudioTrack(int streamType, int sampleRateInHz, int channelConfig, int audioFormat, int bufferSizeInBytes, int mode)边采集边播放PCM代码(仅核心代码, 不完整)//Audio Parameter static class AudioParam{ static final int FREQ_8000 = 8000; static final int FREQ_11025 = 11025; static final int FREQ_16000 = 16000; static final int FREQ_22050 = 22050; static final int FREQ_44100 = 44100; static final int FREQ_96000 = 96000; int device; int channel; int bitFormat; int buffSize; //int doubleBuffSize; int buffSizeOut; int rate; public AudioParam(int device, int rate, int channel, int bitFormat){ this.device = device; this.rate = rate; this.channel = channel; this.bitFormat = bitFormat; initBufferSize(); } private void initBufferSize() { buffSize = AudioRecord.getMinBufferSize(rate, channel, bitFormat); buffSizeOut = AudioTrack.getMinBufferSize(rate, channel, bitFormat); Logger.d("AudioPCM", "buffSize(" + buffSize + "), buffSizeOut(" + buffSizeOut + ")"); if(buffSizeOut < 0)buffSizeOut = buffSize; //doubleBuffSize = buffSize * 2; } static AudioParam getDefaultInParam(){ return new AudioParam(MediaRecorder.AudioSource.MIC, FREQ_44100, AudioFormat.CHANNEL_CONFIGURATION_DEFAULT, AudioFormat.ENCODING_PCM_16BIT); } static AudioParam getDefaultOutParam(){ return new AudioParam(AudioManager.STREAM_MUSIC, FREQ_44100, AudioFormat.CHANNEL_CONFIGURATION_DEFAULT, AudioFormat.ENCODING_PCM_16BIT); } } //Thread for capture audio class CaptureThread extends Thread{ @Override public void run() { AudioRecord mic = new AudioRecord(audioParamIn.device, audioParamIn.rate, audioParamIn.channel, audioParamIn.bitFormat, audioParamIn.buffSize); mic.startRecording(); byte[] pcmBuffer = new byte[2048]; while (!Thread.interrupted()) { int size = mic.read(pcmBuffer, 0, pcmBuffer.length); Logger.d(TAG, "read " + size + " bytes"); if (size <= 0) { break; }else{ if(playThd != null){ playThd.write(pcmBuffer, size); } } } mic.stop(); mic.release(); } } //Thread for play class PlayThread{ private AudioTrack mAudioTrack; PlayThread(){ try { audioParamOut = new AudioParam(AudioManager.STREAM_MUSIC, AudioParam.FREQ_44100, AudioFormat.CHANNEL_CONFIGURATION_DEFAULT, AudioFormat.ENCODING_PCM_16BIT); createAudioTrack(); mAudioTrack.play(); } catch (Exception e) { e.printStackTrace(); } } void write(byte[] bs, int size){ Logger.d(TAG, "write " + size + " bytes"); if(mAudioTrack != null){ mAudioTrack.write(bs, 0, size); } } void stop(){ if(mAudioTrack != null){ mAudioTrack.stop(); } } private void createAudioTrack() throws Exception{ // STREAM_ALARM:警告声 // STREAM_MUSCI:音乐声,例如music等 // STREAM_RING:铃声 // STREAM_SYSTEM:系统声音 // STREAM_VOCIE_CALL:电话声音 mAudioTrack = new AudioTrack(audioParamOut.device, audioParamOut.rate, audioParamOut.channel, audioParamOut.bitFormat, audioParamOut.buffSizeOut, AudioTrack.MODE_STREAM); } }扩展需要确定能正常的识别到USB 摄像头的MIC输入设备(这个过程走了许多弯路)在测试过程中发现 MediaRecorder.AudioSource.CAMCORDER, MediaRecorder.AudioSource.MIC对应的设备并不是固定的当未接USB摄像头的时候 MediaRecorder.AudioSource.MIC 对应的是 主板的MIC当接上USB摄像头后, MediaRecorder.AudioSource.MIC 对应的是USB摄像头上的MIC.参考关于USB-Audio(USB麦克风)设备的录音验证Android usb audio录音Android下音频的测试程序tinyalsa(录音,放音,查看声卡信息)Android语音采集
1.概况为服务器重装了Ubuntu 16.04-server, 之前的一些数据丢失了, 好在硬盘并未格式化, 至少还有点希望能恢复Mysql的数据2.现有条件把旧的硬盘挂载到电脑上, 找到数据库目录下的文件: 默认的数据库目录为: /var/lib/mysql硬盘挂载目录为: /media/user/f101a309-d55a-4a50-8e1c-d63534146b6f$ ll /media/user/f101a309-d55a-4a50-8e1c-d63534146b6f/var/lib/mysql -rw-r----- 1 122 vboxusers 56 9月 6 2019 auto.cnf -rw------- 1 122 vboxusers 1680 11月 19 06:09 ca-key.pem -rw-r--r-- 1 122 vboxusers 1112 11月 19 06:09 ca.pem -rw-r--r-- 1 122 vboxusers 1112 11月 19 06:09 client-cert.pem -rw------- 1 122 vboxusers 1676 11月 19 06:09 client-key.pem -rw-r--r-- 1 122 vboxusers 0 2月 25 09:40 debian-5.7.flag drwxr-x--- 2 122 vboxusers 4096 9月 17 2019 FactoryTest/ -rw-r----- 1 122 vboxusers 750 4月 1 09:07 ib_buffer_pool -rw-r----- 1 122 vboxusers 79691776 4月 1 09:07 ibdata1 -rw-r----- 1 122 vboxusers 50331648 4月 1 09:07 ib_logfile0 -rw-r----- 1 122 vboxusers 50331648 9月 6 2019 ib_logfile1 drwxr-x--- 2 122 vboxusers 4096 10月 22 15:27 kanboard/ drwxr-x--- 2 122 vboxusers 4096 2月 25 09:41 mysql/ -rw-r--r-- 1 122 vboxusers 6 2月 25 09:41 mysql_upgrade_info drwxr-x--- 2 122 vboxusers 4096 2月 25 09:40 performance_schema/ -rw------- 1 122 vboxusers 1676 11月 19 06:09 private_key.pem -rw-r--r-- 1 122 vboxusers 452 11月 19 06:09 public_key.pem -rw-r--r-- 1 122 vboxusers 1112 11月 19 06:09 server-cert.pem -rw------- 1 122 vboxusers 1680 11月 19 06:09 server-key.pem drwxr-x--- 2 122 vboxusers 12288 11月 19 06:09 sys/ drwxr-x--- 2 122 vboxusers 12288 10月 22 10:18 zentao/需要恢复的数据库 FactoryTest, 所以, 不管如何先将它压缩保存下来, 丢到服务器去试试先.3.粗暴的尝试停止mysql /etc/init.d/mysql stop直接把上面找到的文件丢到服务器对应的mysql目录下, 并修改相应的文件权限启动mysql /etc/init.d/mysql start尝试访问读取数据失败…果然没那么简单.停止数据库, 删除前面的暴力尝试拷贝进去的文件夹4.Google 后, 见参考.14.1恢复表格需要用到工具mysqlfrm找不到, 就装一个sudo apt install mysql-utilities命令执行的效果 mysqlfrm --diagnostic FactoryTest/Wifi.frm# WARNING: Cannot generate character set or collation names without the --server option. # CAUTION: The diagnostic mode is a best-effort parse of the .frm file. As such, it may not identify all of the components of the table correctly. This is especially true for damaged files. It will also not read the default values for the columns and the resulting statement may not be syntactically correct. # Reading .frm file for FactoryTest/Wifi.frm: # The .frm file is a TABLE. # CREATE TABLE Statement: CREATE TABLE `FactoryTest`.`Wifi` ( `id` int(11) NOT NULL AUTO_INCREMENT, `ssid` varchar(32) NOT NULL, `pwd` varchar(32) NOT NULL, PRIMARY KEY `PRIMARY` (`id`) ) ENGINE=InnoDB; #...done.表格的query语句出来了, 接下来就简单了, 拷贝粘贴, 执行完, 表格都有了.4.2恢复数据进mysql执行下面的命令(所有的表格):ALTER TABLE example_table DISCARD TABLESPACE;执行完后, 数据库目录下的 .idb 文件都不见了执行上面的暴力拷贝, 只拷贝 .idb 文件: sudo cp -rn . /var/lib/mysql/FactoryTest/记得修改文件权限: sudo chown mysql:mysql -R /var/lib/mysql/FactoryTest再进mysql为每个表格执行语句ALTER TABLE example_table IMPORT TABLESPACE;完成5.参考1. Restore table structure from frm and ibd files2. Reset a MySQL root password
平台RK3368 + android 7.1问题在做重启测试的过程中, 重启程序的启动速度越来越慢, 如以下LOG://第一天 [20.354000 s,20.354000 s] 01-18 16:51:21.606 D/ActivityManager( 469): Sending BOOT_COMPLETE user #0 [20.793000 s,0.439000 s] 01-18 16:51:22.045 I/AlarmClock( 961): AlarmInitReceiver android.intent.action.LOCKED_BOOT_COMPLETED [23.543000 s,2.750000 s] 01-18 16:51:24.795 D/HdmiReceiver( 635): hdmi receiver action=android.intent.action.BOOT_COMPLETED //第二天 [20.127000 s,20.127000 s] 01-19 18:57:57.513 438 499 D ActivityManager: Sending BOOT_COMPLETE user #0 [20.354000 s,0.227000 s] 01-19 18:57:57.740 960 960 I AlarmClock: AlarmInitReceiver android.intent.action.LOCKED_BOOT_COMPLETED [36.911000 s,16.557000 s] 01-19 18:58:14.297 635 635 D HdmiReceiver: hdmi receiver action=android.intent.action.BOOT_COMPLETED //第三天 [23.242000 s,23.242000 s] 01-20 14:10:07.611 436 497 D ActivityManager: Sending BOOT_COMPLETE user #0 [23.507000 s,0.265000 s] 01-20 14:10:07.876 961 961 I AlarmClock: AlarmInitReceiver android.intent.action.LOCKED_BOOT_COMPLETED [47.177000 s,23.670000 s] 01-20 14:10:31.546 629 629 D HdmiReceiver: hdmi receiver action=android.intent.action.BOOT_COMPLETED每天 10’s + ??解决QSB = QuickSearchBox方案1: 优化Launcher中添加QSB的代码diff --git a/packages/apps/Launcher3/src/com/android/launcher3/QsbContainerView.java b/packages/apps/Launcher3/src/com/android/launcher3/QsbContainerView.java index ffed8fc..811b42a 100755 --- a/packages/apps/Launcher3/src/com/android/launcher3/QsbContainerView.java +++ b/packages/apps/Launcher3/src/com/android/launcher3/QsbContainerView.java @@ -103,7 +103,6 @@ public class QsbContainerView extends FrameLayout { mWrapper.addView(createQsb(inflater, mWrapper)); return mWrapper; } - private View createQsb(LayoutInflater inflater, ViewGroup container) { Launcher launcher = Launcher.getLauncher(getActivity()); mWidgetInfo = getSearchWidgetProvider(launcher); @@ -128,7 +127,6 @@ public class QsbContainerView extends FrameLayout { AppWidgetProviderInfo widgetInfo = widgetManager.getAppWidgetInfo(widgetId); boolean isWidgetBound = (widgetInfo != null) && widgetInfo.provider.equals(mWidgetInfo.provider); - if (!isWidgetBound) { // widgetId is already bound and its not the correct provider. // Delete the widget id. @@ -142,6 +140,9 @@ public class QsbContainerView extends FrameLayout { if (!isWidgetBound) { widgetHost.deleteAppWidgetId(widgetId); widgetId = -1; + }else{//添加成功后, 保持ID, 避免重复添加 + sSavedWidgetId = widgetId; + prefs.edit().putInt(QSB_WIDGET_ID, widgetId).commit(); } }方案2: 更换其它Launcher方案3: 删除QSB方案4: 优化系统Widget服务(请自行开发)分析首先了解下BOOT_COMPLETED, 绝大部分的应用自启动所依赖的广播:发出的过程如下:WindowManagerService.performEnableScreenActivityManagerService.bootAnimationCompleteActivityManagerService.finishBootingUserController.sendBootCompletedLockedUserController.finishUserBootUserController.maybeUnlockUserUserController.unlockUserClearedUserController.finishUserUnlocking部分代码frameworks/base/services/core/java/com/android/server/am/UserController.javaboolean unlockUser(final int userId, byte[] token, byte[] secret, IProgressListener listener) { //... try { return unlockUserCleared(userId, token, secret, listener); } finally { Binder.restoreCallingIdentity(binderToken); } } /** * Attempt to unlock user without a credential token. This typically * succeeds when the device doesn't have credential-encrypted storage, or * when the the credential-encrypted storage isn't tied to a user-provided * PIN or pattern. */ boolean maybeUnlockUser(final int userId) { // Try unlocking storage using empty token return unlockUserCleared(userId, null, null, null); } boolean unlockUserCleared(final int userId, byte[] token, byte[] secret, IProgressListener listener) { //... finishUserUnlocking(uss); } private void finishUserUnlocking(final UserState uss) { //... if (proceedWithUnlock) { uss.mUnlockProgress.start(); // Prepare app storage before we go any further uss.mUnlockProgress.setProgress(5, mService.mContext.getString(R.string.android_start_title)); mUserManager.onBeforeUnlockUser(userId); uss.mUnlockProgress.setProgress(20); // Dispatch unlocked to system services; when fully dispatched, // that calls through to the next "unlocked" phase mHandler.obtainMessage(SYSTEM_USER_UNLOCK_MSG, userId, 0, uss) .sendToTarget(); } }frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.javafinal class MainHandler extends Handler { //... case SYSTEM_USER_UNLOCK_MSG: { final int userId = msg.arg1; mSystemServiceManager.unlockUser(userId); synchronized (ActivityManagerService.this) { mRecentTasks.loadUserRecentsLocked(userId); } if (userId == UserHandle.USER_SYSTEM) { startPersistentApps(PackageManager.MATCH_DIRECT_BOOT_UNAWARE); } installEncryptionUnawareProviders(userId); mUserController.finishUserUnlocked((UserState) msg.obj); break; } //...frameworks/base/services/core/java/com/android/server/am/UserController.javavoid finishUserUnlocked(final UserState uss) { //... new PreBootBroadcaster(mService, userId, null, quiet) { @Override public void onFinished() { finishUserUnlockedCompleted(uss); } }.sendNext(); } else { finishUserUnlockedCompleted(uss); } //... } private void finishUserUnlockedCompleted(UserState uss) { //... Slog.d(TAG, "Sending BOOT_COMPLETE user #" + userId); //... final Intent bootIntent = new Intent(Intent.ACTION_BOOT_COMPLETED, null); bootIntent.putExtra(Intent.EXTRA_USER_HANDLE, userId); bootIntent.addFlags(Intent.FLAG_RECEIVER_NO_ABORT | Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND); mService.broadcastIntentLocked(null, null, bootIntent, null, null, 0, null, null, new String[] { android.Manifest.permission.RECEIVE_BOOT_COMPLETED }, AppOpsManager.OP_NONE, null, true, false, MY_PID, SYSTEM_UID, userId); //... }frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.javafinal int broadcastIntentLocked(ProcessRecord callerApp, String callerPackage, Intent intent, String resolvedType, IIntentReceiver resultTo, int resultCode, String resultData, Bundle resultExtras, String[] requiredPermissions, int appOp, Bundle bOptions, boolean ordered, boolean sticky, int callingPid, int callingUid, int userId) { intent = new Intent(intent); //... queue.enqueueOrderedBroadcastLocked(r); queue.scheduleBroadcastsLocked(); //... }frameworks/base/services/core/java/com/android/server/am/BroadcastQueue.javapublic void enqueueOrderedBroadcastLocked(BroadcastRecord r) { mOrderedBroadcasts.add(r); r.enqueueClockTime = System.currentTimeMillis(); } public void scheduleBroadcastsLocked() { if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Schedule broadcasts [" + mQueueName + "]: current=" + mBroadcastsScheduled); if (mBroadcastsScheduled) { return; } mHandler.sendMessage(mHandler.obtainMessage(BROADCAST_INTENT_MSG, this)); mBroadcastsScheduled = true; }剩下的, 就看BroadcastQueue这个队列的执行情况了.是谁拖慢了时间?UserController中调用ActivityManagerService发出广播, 的时间其实并没有太大差距, 真正的差距, 是从加入队列后到接收的时间长.//第三天 [23.242000 s,23.242000 s] 01-20 14:10:07.611 436 497 D ActivityManager: Sending BOOT_COMPLETE user #0 [23.507000 s,0.265000 s] 01-20 14:10:07.876 961 961 I AlarmClock: AlarmInitReceiver android.intent.action.LOCKED_BOOT_COMPLETED [47.177000 s,23.670000 s] 01-20 14:10:31.546 629 629 D HdmiReceiver: hdmi receiver action=android.intent.action.BOOT_COMPLETED如上, 从 Sending 到 Receiver接收到, 用了24’s从当前的LOG上, 没有更多的有效信息, 了解了广播的发送流程, 尝试打开调试开关frameworks/base/services/core/java/com/android/server/am/ActivityManagerDebugConfig.java@@ -49,7 +49,7 @@ class ActivityManagerDebugConfig { static final boolean DEBUG_ANR = false; static final boolean DEBUG_APP = DEBUG_ALL_ACTIVITIES || false; static final boolean DEBUG_BACKUP = DEBUG_ALL || false; - static final boolean DEBUG_BROADCAST = DEBUG_ALL || false; + static final boolean DEBUG_BROADCAST = DEBUG_ALL || true; static final boolean DEBUG_BROADCAST_BACKGROUND = DEBUG_BROADCAST || false; static final boolean DEBUG_BROADCAST_LIGHT = DEBUG_BROADCAST || false; static final boolean DEBUG_CLEANUP = DEBUG_ALL || false;得到了一个很有趣的LOG信息:01-18 17:34:11.199 D/ActivityManager( 444): Sending BOOT_COMPLETE user #0 01-18 17:34:11.199 V/ActivityManager( 444): Broadcast: Intent { act=android.intent.action.BOOT_COMPLETED flg=0x9000010 (has extras) } ordered=true userid=0 01-18 17:34:11.201 V/ActivityManager( 444): Enqueing broadcast: android.intent.action.BOOT_COMPLETED replacePending=false 01-18 17:34:11.201 I/ActivityManager( 444): Broadcast intent Intent { act=android.intent.action.BOOT_COMPLETED flg=0x9000010 (has extras) } on background queue 01-18 17:34:11.201 V/ActivityManager( 444): Enqueueing ordered broadcast BroadcastRecord{1c9d3ec u0 android.intent.action.BOOT_COMPLETED}: prev had 4 01-18 17:34:11.201 I/ActivityManager( 444): Enqueueing broadcast android.intent.action.BOOT_COMPLETED 01-18 17:34:38.115 V/BroadcastQueue( 444): Processing ordered broadcast [background] BroadcastRecord{1c9d3ec u0 android.intent.action.BOOT_COMPLETED} 01-18 17:34:38.115 V/BroadcastQueue( 444): Submitting BROADCAST_TIMEOUT_MSG [background] for BroadcastRecord{1c9d3ec u0 android.intent.action.BOOT_COMPLETED} at 108628 01-18 17:34:38.116 V/BroadcastQueue( 444): Delivering ordered [background] to registered BroadcastFilter{84ddfd0 u-1 ReceiverList{cf4e393 444 system/1000/u-1 local:5386082}}: BroadcastRecord{1c9d3ec u0 android.intent.action.BOOT_COMPLETED} 01-18 17:34:38.116 I/BroadcastQueue( 444): Delivering to BroadcastFilter{84ddfd0 u-1 ReceiverList{cf4e393 444 system/1000/u-1 local:5386082}} : BroadcastRecord{1c9d3ec u0 android.intent.action.BOOT_COMPLETED}在BOOT_COMPLETED前有一个广播:01-18 17:34:12.715 V/ActivityManager( 444): Broadcast: Intent { act=android.appwidget.action.APPWIDGET_UPDATE flg=0x10 cmp=com.android.quicksearchbox/.SearchWidgetProvider (has extras) } ordered=false userid=0 01-18 17:34:12.715 V/ActivityManager( 444): Enqueing broadcast: android.appwidget.action.APPWIDGET_UPDATE replacePending=false 01-18 17:34:12.715 I/ActivityManager( 444): Broadcast intent Intent { act=android.appwidget.action.APPWIDGET_UPDATE flg=0x10 cmp=com.android.quicksearchbox/.SearchWidgetProvider (has extras) } on background queue 01-18 17:34:12.715 V/ActivityManager( 444): Enqueueing ordered broadcast BroadcastRecord{afaca5f u0 android.appwidget.action.APPWIDGET_UPDATE}: prev had 5 01-18 17:34:12.715 I/ActivityManager( 444): Enqueueing broadcast android.appwidget.action.APPWIDGET_UPDATE 01-18 17:34:38.115 V/BroadcastQueue( 444): Finished with ordered broadcast BroadcastRecord{a4ae1fd u0 android.appwidget.action.APPWIDGET_UPDATE}从LOG中, com.android.quicksearchbox出现了, 直观让我把QuickSearchBox删除了再试试, 问题真的解决了, 重启一天也没出现类似问题, 所以肯定跟QuickSearchBox有关.frameworks/base/services/core/java/com/android/server/am/BroadcastQueue.java(输出更多的LOG)final void processNextBroadcast(boolean fromMsg) { if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "processNextBroadcast start"); synchronized(mService) { BroadcastRecord r; if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "processNextBroadcast [" + mQueueName + "]: " + mParallelBroadcasts.size() + " broadcasts, " + mOrderedBroadcasts.size() + " ordered broadcasts"); mService.updateCpuStats(); if (fromMsg) { mBroadcastsScheduled = false; } // First, deliver any non-serialized broadcasts right away. while (mParallelBroadcasts.size() > 0) { if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "processNextBroadcast 0"); r = mParallelBroadcasts.remove(0); r.dispatchTime = SystemClock.uptimeMillis(); r.dispatchClockTime = System.currentTimeMillis(); final int N = r.receivers.size(); if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG_BROADCAST, "Processing parallel broadcast [" + mQueueName + "] " + r); for (int i=0; i<N; i++) { Object target = r.receivers.get(i); if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Delivering non-ordered on [" + mQueueName + "] to registered " + target + ": " + r); deliverToRegisteredReceiverLocked(r, (BroadcastFilter)target, false, i); } addBroadcastToHistoryLocked(r); if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG_BROADCAST, "Done with parallel broadcast [" + mQueueName + "] " + r); } // Now take care of the next serialized one... // If we are waiting for a process to come up to handle the next // broadcast, then do nothing at this point. Just in case, we // check that the process we're waiting for still exists. if (mPendingBroadcast != null) { if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG_BROADCAST, "processNextBroadcast [" + mQueueName + "]: waiting for " + mPendingBroadcast.curApp); boolean isDead; synchronized (mService.mPidsSelfLocked) { ProcessRecord proc = mService.mPidsSelfLocked.get(mPendingBroadcast.curApp.pid); isDead = proc == null || proc.crashing; } if (!isDead) { // It's still alive, so keep waiting return; } else { Slog.w(TAG, "pending app [" + mQueueName + "]" + mPendingBroadcast.curApp + " died before responding to broadcast"); mPendingBroadcast.state = BroadcastRecord.IDLE; mPendingBroadcast.nextReceiver = mPendingBroadcastRecvIndex; mPendingBroadcast = null; } } boolean looped = false; do { if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "processNextBroadcast 1"); if (mOrderedBroadcasts.size() == 0) { // No more broadcasts pending, so all done! mService.scheduleAppGcsLocked(); if (looped) { // If we had finished the last ordered broadcast, then // make sure all processes have correct oom and sched // adjustments. mService.updateOomAdjLocked(); } return; } r = mOrderedBroadcasts.get(0); boolean forceReceive = false; // Ensure that even if something goes awry with the timeout // detection, we catch "hung" broadcasts here, discard them, // and continue to make progress. // // This is only done if the system is ready so that PRE_BOOT_COMPLETED // receivers don't get executed with timeouts. They're intended for // one time heavy lifting after system upgrades and can take // significant amounts of time. int numReceivers = (r.receivers != null) ? r.receivers.size() : 0; if (mService.mProcessesReady && r.dispatchTime > 0) { long now = SystemClock.uptimeMillis(); if ((numReceivers > 0) && (now > r.dispatchTime + (2*mTimeoutPeriod*numReceivers))) { Slog.w(TAG, "Hung broadcast [" + mQueueName + "] discarded after timeout failure:" + " now=" + now + " dispatchTime=" + r.dispatchTime + " startTime=" + r.receiverTime + " intent=" + r.intent + " numReceivers=" + numReceivers + " nextReceiver=" + r.nextReceiver + " state=" + r.state); broadcastTimeoutLocked(false); // forcibly finish this broadcast forceReceive = true; r.state = BroadcastRecord.IDLE; } } if (r.state != BroadcastRecord.IDLE) { if (DEBUG_BROADCAST) Slog.d(TAG_BROADCAST, "processNextBroadcast(" + mQueueName + ") called when not idle (state=" + r.state + ")"); return; } if (r.receivers == null || r.nextReceiver >= numReceivers || r.resultAbort || forceReceive) { // No more receivers for this broadcast! Send the final // result if requested... if (r.resultTo != null) { try { if (DEBUG_BROADCAST) Slog.i(TAG_BROADCAST, "Finishing broadcast [" + mQueueName + "] " + r.intent.getAction() + " app=" + r.callerApp); performReceiveLocked(r.callerApp, r.resultTo, new Intent(r.intent), r.resultCode, r.resultData, r.resultExtras, false, false, r.userId); // Set this to null so that the reference // (local and remote) isn't kept in the mBroadcastHistory. r.resultTo = null; } catch (RemoteException e) { r.resultTo = null; Slog.w(TAG, "Failure [" + mQueueName + "] sending broadcast result of " + r.intent, e); } } if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Cancelling BROADCAST_TIMEOUT_MSG"); cancelBroadcastTimeoutLocked(); if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG_BROADCAST, "Finished with ordered broadcast " + r); // ... and on to the next... addBroadcastToHistoryLocked(r); if (r.intent.getComponent() == null && r.intent.getPackage() == null && (r.intent.getFlags()&Intent.FLAG_RECEIVER_REGISTERED_ONLY) == 0) { // This was an implicit broadcast... let's record it for posterity. mService.addBroadcastStatLocked(r.intent.getAction(), r.callerPackage, r.manifestCount, r.manifestSkipCount, r.finishTime-r.dispatchTime); } mOrderedBroadcasts.remove(0); r = null; looped = true; continue; } } while (r == null); // Get the next receiver... int recIdx = r.nextReceiver++; // Keep track of when this receiver started, and make sure there // is a timeout message pending to kill it if need be. r.receiverTime = SystemClock.uptimeMillis(); if (recIdx == 0) { r.dispatchTime = r.receiverTime; r.dispatchClockTime = System.currentTimeMillis(); if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG_BROADCAST, "Processing ordered broadcast [" + mQueueName + "] " + r); } if (! mPendingBroadcastTimeoutMessage) { long timeoutTime = r.receiverTime + mTimeoutPeriod; if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Submitting BROADCAST_TIMEOUT_MSG [" + mQueueName + "] for " + r + " at " + timeoutTime); setBroadcastTimeoutLocked(timeoutTime); } final BroadcastOptions brOptions = r.options; final Object nextReceiver = r.receivers.get(recIdx); if (nextReceiver instanceof BroadcastFilter) { // Simple case: this is a registered receiver who gets // a direct call. BroadcastFilter filter = (BroadcastFilter)nextReceiver; if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Delivering ordered [" + mQueueName + "] to registered " + filter + ": " + r); deliverToRegisteredReceiverLocked(r, filter, r.ordered, recIdx); if (r.receiver == null || !r.ordered) { // The receiver has already finished, so schedule to // process the next one. if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Quick finishing [" + mQueueName + "]: ordered=" + r.ordered + " receiver=" + r.receiver); r.state = BroadcastRecord.IDLE; scheduleBroadcastsLocked(); } else { if (brOptions != null && brOptions.getTemporaryAppWhitelistDuration() > 0) { scheduleTempWhitelistLocked(filter.owningUid, brOptions.getTemporaryAppWhitelistDuration(), r); } } return; } if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "processNextBroadcast 2"); // Hard case: need to instantiate the receiver, possibly // starting its application process to host it. ResolveInfo info = (ResolveInfo)nextReceiver; ComponentName component = new ComponentName( info.activityInfo.applicationInfo.packageName, info.activityInfo.name); boolean skip = false; if (brOptions != null && (info.activityInfo.applicationInfo.targetSdkVersion < brOptions.getMinManifestReceiverApiLevel() || info.activityInfo.applicationInfo.targetSdkVersion > brOptions.getMaxManifestReceiverApiLevel())) { skip = true; } int perm = mService.checkComponentPermission(info.activityInfo.permission, r.callingPid, r.callingUid, info.activityInfo.applicationInfo.uid, info.activityInfo.exported); if (!skip && perm != PackageManager.PERMISSION_GRANTED) { if (!info.activityInfo.exported) { Slog.w(TAG, "Permission Denial: broadcasting " + r.intent.toString() + " from " + r.callerPackage + " (pid=" + r.callingPid + ", uid=" + r.callingUid + ")" + " is not exported from uid " + info.activityInfo.applicationInfo.uid + " due to receiver " + component.flattenToShortString()); } else { Slog.w(TAG, "Permission Denial: broadcasting " + r.intent.toString() + " from " + r.callerPackage + " (pid=" + r.callingPid + ", uid=" + r.callingUid + ")" + " requires " + info.activityInfo.permission + " due to receiver " + component.flattenToShortString()); } skip = true; } else if (!skip && info.activityInfo.permission != null) { final int opCode = AppOpsManager.permissionToOpCode(info.activityInfo.permission); if (opCode != AppOpsManager.OP_NONE && mService.mAppOpsService.noteOperation(opCode, r.callingUid, r.callerPackage) != AppOpsManager.MODE_ALLOWED) { Slog.w(TAG, "Appop Denial: broadcasting " + r.intent.toString() + " from " + r.callerPackage + " (pid=" + r.callingPid + ", uid=" + r.callingUid + ")" + " requires appop " + AppOpsManager.permissionToOp( info.activityInfo.permission) + " due to registered receiver " + component.flattenToShortString()); skip = true; } } if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "processNextBroadcast 3"); if (!skip && info.activityInfo.applicationInfo.uid != Process.SYSTEM_UID && r.requiredPermissions != null && r.requiredPermissions.length > 0) { for (int i = 0; i < r.requiredPermissions.length; i++) { String requiredPermission = r.requiredPermissions[i]; try { perm = AppGlobals.getPackageManager(). checkPermission(requiredPermission, info.activityInfo.applicationInfo.packageName, UserHandle .getUserId(info.activityInfo.applicationInfo.uid)); } catch (RemoteException e) { perm = PackageManager.PERMISSION_DENIED; } if (perm != PackageManager.PERMISSION_GRANTED) { Slog.w(TAG, "Permission Denial: receiving " + r.intent + " to " + component.flattenToShortString() + " requires " + requiredPermission + " due to sender " + r.callerPackage + " (uid " + r.callingUid + ")"); skip = true; break; } int appOp = AppOpsManager.permissionToOpCode(requiredPermission); if (appOp != AppOpsManager.OP_NONE && appOp != r.appOp && mService.mAppOpsService.noteOperation(appOp, info.activityInfo.applicationInfo.uid, info.activityInfo.packageName) != AppOpsManager.MODE_ALLOWED) { Slog.w(TAG, "Appop Denial: receiving " + r.intent + " to " + component.flattenToShortString() + " requires appop " + AppOpsManager.permissionToOp( requiredPermission) + " due to sender " + r.callerPackage + " (uid " + r.callingUid + ")"); skip = true; break; } } } if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "processNextBroadcast 4"); if (!skip && r.appOp != AppOpsManager.OP_NONE && mService.mAppOpsService.noteOperation(r.appOp, info.activityInfo.applicationInfo.uid, info.activityInfo.packageName) != AppOpsManager.MODE_ALLOWED) { Slog.w(TAG, "Appop Denial: receiving " + r.intent + " to " + component.flattenToShortString() + " requires appop " + AppOpsManager.opToName(r.appOp) + " due to sender " + r.callerPackage + " (uid " + r.callingUid + ")"); skip = true; } if (!skip) { skip = !mService.mIntentFirewall.checkBroadcast(r.intent, r.callingUid, r.callingPid, r.resolvedType, info.activityInfo.applicationInfo.uid); } boolean isSingleton = false; try { isSingleton = mService.isSingleton(info.activityInfo.processName, info.activityInfo.applicationInfo, info.activityInfo.name, info.activityInfo.flags); } catch (SecurityException e) { Slog.w(TAG, e.getMessage()); skip = true; } if ((info.activityInfo.flags&ActivityInfo.FLAG_SINGLE_USER) != 0) { if (ActivityManager.checkUidPermission( android.Manifest.permission.INTERACT_ACROSS_USERS, info.activityInfo.applicationInfo.uid) != PackageManager.PERMISSION_GRANTED) { Slog.w(TAG, "Permission Denial: Receiver " + component.flattenToShortString() + " requests FLAG_SINGLE_USER, but app does not hold " + android.Manifest.permission.INTERACT_ACROSS_USERS); skip = true; } } if (!skip) { r.manifestCount++; } else { r.manifestSkipCount++; } if (r.curApp != null && r.curApp.crashing) { // If the target process is crashing, just skip it. Slog.w(TAG, "Skipping deliver ordered [" + mQueueName + "] " + r + " to " + r.curApp + ": process crashing"); skip = true; } if (!skip) { boolean isAvailable = false; try { isAvailable = AppGlobals.getPackageManager().isPackageAvailable( info.activityInfo.packageName, UserHandle.getUserId(info.activityInfo.applicationInfo.uid)); } catch (Exception e) { // all such failures mean we skip this receiver Slog.w(TAG, "Exception getting recipient info for " + info.activityInfo.packageName, e); } if (!isAvailable) { if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Skipping delivery to " + info.activityInfo.packageName + " / " + info.activityInfo.applicationInfo.uid + " : package no longer available"); skip = true; } } // If permissions need a review before any of the app components can run, we drop // the broadcast and if the calling app is in the foreground and the broadcast is // explicit we launch the review UI passing it a pending intent to send the skipped // broadcast. if ((mService.mPermissionReviewRequired || Build.PERMISSIONS_REVIEW_REQUIRED) && !skip) { if (!requestStartTargetPermissionsReviewIfNeededLocked(r, info.activityInfo.packageName, UserHandle.getUserId( info.activityInfo.applicationInfo.uid))) { skip = true; } } // This is safe to do even if we are skipping the broadcast, and we need // this information now to evaluate whether it is going to be allowed to run. final int receiverUid = info.activityInfo.applicationInfo.uid; // If it's a singleton, it needs to be the same app or a special app if (r.callingUid != Process.SYSTEM_UID && isSingleton && mService.isValidSingletonCall(r.callingUid, receiverUid)) { info.activityInfo = mService.getActivityInfoForUser(info.activityInfo, 0); } String targetProcess = info.activityInfo.processName; ProcessRecord app = mService.getProcessRecordLocked(targetProcess, info.activityInfo.applicationInfo.uid, false); if (!skip) { final int allowed = mService.checkAllowBackgroundLocked( info.activityInfo.applicationInfo.uid, info.activityInfo.packageName, -1, false); if (allowed != ActivityManager.APP_START_MODE_NORMAL) { // We won't allow this receiver to be launched if the app has been // completely disabled from launches, or it was not explicitly sent // to it and the app is in a state that should not receive it // (depending on how checkAllowBackgroundLocked has determined that). if (allowed == ActivityManager.APP_START_MODE_DISABLED) { Slog.w(TAG, "Background execution disabled: receiving " + r.intent + " to " + component.flattenToShortString()); skip = true; } else if (((r.intent.getFlags()&Intent.FLAG_RECEIVER_EXCLUDE_BACKGROUND) != 0) || (r.intent.getComponent() == null && r.intent.getPackage() == null && ((r.intent.getFlags() & Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND) == 0))) { Slog.w(TAG, "Background execution not allowed: receiving " + r.intent + " to " + component.flattenToShortString()); skip = true; } } } if (skip) { if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Skipping delivery of ordered [" + mQueueName + "] " + r + " for whatever reason"); r.delivery[recIdx] = BroadcastRecord.DELIVERY_SKIPPED; r.receiver = null; r.curFilter = null; r.state = BroadcastRecord.IDLE; scheduleBroadcastsLocked(); return; } if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "processNextBroadcast 5"); r.delivery[recIdx] = BroadcastRecord.DELIVERY_DELIVERED; r.state = BroadcastRecord.APP_RECEIVE; r.curComponent = component; r.curReceiver = info.activityInfo; if (DEBUG_MU && r.callingUid > UserHandle.PER_USER_RANGE) { Slog.v(TAG_MU, "Updated broadcast record activity info for secondary user, " + info.activityInfo + ", callingUid = " + r.callingUid + ", uid = " + info.activityInfo.applicationInfo.uid); } if (brOptions != null && brOptions.getTemporaryAppWhitelistDuration() > 0) { scheduleTempWhitelistLocked(receiverUid, brOptions.getTemporaryAppWhitelistDuration(), r); } // Broadcast is being executed, its package can't be stopped. try { AppGlobals.getPackageManager().setPackageStoppedState( r.curComponent.getPackageName(), false, UserHandle.getUserId(r.callingUid)); } catch (RemoteException e) { } catch (IllegalArgumentException e) { Slog.w(TAG, "Failed trying to unstop package " + r.curComponent.getPackageName() + ": " + e); } // Is this receiver's application already running? if (app != null && app.thread != null) { try { if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "processNextBroadcast app already running"); app.addPackage(info.activityInfo.packageName, info.activityInfo.applicationInfo.versionCode, mService.mProcessStats); processCurBroadcastLocked(r, app); if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "processNextBroadcast 1230"); return; } catch (RemoteException e) { Slog.w(TAG, "Exception when sending broadcast to " + r.curComponent, e); } catch (RuntimeException e) { Slog.wtf(TAG, "Failed sending broadcast to " + r.curComponent + " with " + r.intent, e); // If some unexpected exception happened, just skip // this broadcast. At this point we are not in the call // from a client, so throwing an exception out from here // will crash the entire system instead of just whoever // sent the broadcast. logBroadcastReceiverDiscardLocked(r); finishReceiverLocked(r, r.resultCode, r.resultData, r.resultExtras, r.resultAbort, false); scheduleBroadcastsLocked(); // We need to reset the state if we failed to start the receiver. r.state = BroadcastRecord.IDLE; return; } // If a dead object exception was thrown -- fall through to // restart the application. } //.... } }01-18 17:01:31.946 V/BroadcastQueue( 436): Processing ordered broadcast [background] BroadcastRecord{cca3571 u0 android.appwidget.action.APPWIDGET_UPDATE} 01-18 17:01:31.946 V/BroadcastQueue( 436): Submitting BROADCAST_TIMEOUT_MSG [background] for BroadcastRecord{cca3571 u0 android.appwidget.action.APPWIDGET_UPDATE} at 90739 01-18 17:01:31.946 V/BroadcastQueue( 436): processNextBroadcast 2 01-18 17:01:31.946 V/BroadcastQueue( 436): processNextBroadcast 3 01-18 17:01:31.946 V/BroadcastQueue( 436): processNextBroadcast 4 01-18 17:01:31.950 V/BroadcastQueue( 436): processNextBroadcast 5 01-18 17:01:31.951 V/BroadcastQueue( 436): processNextBroadcast app already running 01-18 17:01:31.952 V/BroadcastQueue( 436): Process cur broadcast BroadcastRecord{cca3571 u0 android.appwidget.action.APPWIDGET_UPDATE} for app ProcessRecord{46e1eb2 1154:com.android.quicksearchbox/u0a49} 01-18 17:01:31.954 V/BroadcastQueue( 436): Delivering to component ComponentInfo{com.android.quicksearchbox/com.android.quicksearchbox.SearchWidgetProvider}: BroadcastRecord{cca3571 u0 android.appwidget.action.APPWIDGET_UPDATE} 01-18 17:01:31.958 V/BroadcastQueue( 436): Process cur broadcast BroadcastRecord{cca3571 u0 android.appwidget.action.APPWIDGET_UPDATE} DELIVERED for app ProcessRecord{46e1eb2 1154:com.android.quicksearchbox/u0a49} 01-18 17:01:31.958 V/BroadcastQueue( 436): processCurBroadcastLocked finish 01-18 17:01:31.958 V/BroadcastQueue( 436): processNextBroadcast 1230 //... 01-18 17:02:18.655 V/BroadcastQueue( 436): Finished with ordered broadcast BroadcastRecord{cca3571 u0 android.appwidget.action.APPWIDGET_UPDATE}处理APPWIDGET_UPDATE这个广播花了47’s, 为什么花这么长, 后面再讲.其实 processNextBroadcast 这个函数在 processNextBroadcast 1230的时候已执行完, 没什么干的了, 接下来, BroadcastQueue在等一个信号, 让他再次进入processNextBroadcast.processCurBroadcastLocked(r, app) 做了以下工作:frameworks/base/services/core/java/com/android/server/am/BroadcastQueue.java //... app.thread.scheduleReceiver(new Intent(r.intent), r.curReceiver, mService.compatibilityInfoForPackageLocked(r.curReceiver.applicationInfo), r.resultCode, r.resultData, r.resultExtras, r.ordered, r.userId, app.repProcState); //...frameworks/base/core/java/android/app/ActivityThread.javaprivate class ApplicationThread extends ApplicationThreadNative { //... public final void scheduleReceiver(Intent intent, ActivityInfo info, CompatibilityInfo compatInfo, int resultCode, String data, Bundle extras, boolean sync, int sendingUser, int processState) { android.util.Log.d("BroadcastQueue-ActivityThread", "scheduleReceiver"); updateProcessState(processState, false); ReceiverData r = new ReceiverData(intent, resultCode, data, extras, sync, false, mAppThread.asBinder(), sendingUser); r.info = info; r.compatInfo = compatInfo; sendMessage(H.RECEIVER, r); } //... } //消息处理后调用: private void handleReceiver(ReceiverData data) { // If we are getting ready to gc after going to the background, well // we are back active so skip it. unscheduleGcIdler(); String component = data.intent.getComponent().getClassName(); LoadedApk packageInfo = getPackageInfoNoCheck( data.info.applicationInfo, data.compatInfo); IActivityManager mgr = ActivityManagerNative.getDefault(); BroadcastReceiver receiver; try { java.lang.ClassLoader cl = packageInfo.getClassLoader(); data.intent.setExtrasClassLoader(cl); data.intent.prepareToEnterProcess(); data.setExtrasClassLoader(cl); receiver = (BroadcastReceiver)cl.loadClass(component).newInstance(); } catch (Exception e) { if (DEBUG_BROADCAST) Slog.i(TAG, "Finishing failed broadcast to " + data.intent.getComponent()); data.sendFinished(mgr); throw new RuntimeException( "Unable to instantiate receiver " + component + ": " + e.toString(), e); } try { Application app = packageInfo.makeApplication(false, mInstrumentation); if (localLOGV) Slog.v( TAG, "Performing receive of " + data.intent + ": app=" + app + ", appName=" + app.getPackageName() + ", pkg=" + packageInfo.getPackageName() + ", comp=" + data.intent.getComponent().toShortString() + ", dir=" + packageInfo.getAppDir()); ContextImpl context = (ContextImpl)app.getBaseContext(); sCurrentBroadcastIntent.set(data.intent); receiver.setPendingResult(data); Slog.i("BroadcastQueue-ActivityThread", "handleReceiver 3 " + receiver.getClass().getSimpleName()); receiver.onReceive(context.getReceiverRestrictedContext(), data.intent); } catch (Exception e) { if (DEBUG_BROADCAST) Slog.i(TAG, "Finishing failed broadcast to " + data.intent.getComponent()); data.sendFinished(mgr); if (!mInstrumentation.onException(receiver, e)) { throw new RuntimeException( "Unable to start receiver " + component + ": " + e.toString(), e); } } finally { sCurrentBroadcastIntent.set(null); } if (receiver.getPendingResult() != null) { data.finish();//PendingResult.finish } }执行时间最长的就是receiver.onReceive(context.getReceiverRestrictedContext(), data.intent);, 也就是QuickSearchBox.SearchWidgetProvider中的onReceive执行了相当长的时间.data.finish() 的后续工作:frameworks/base/core/java/android/content/BroadcastReceiver.javapublic abstract class BroadcastReceiver { //... /** * State for a result that is pending for a broadcast receiver. Returned * by {@link BroadcastReceiver#goAsync() goAsync()} * while in {@link BroadcastReceiver#onReceive BroadcastReceiver.onReceive()}. * This allows you to return from onReceive() without having the broadcast * terminate; you must call {@link #finish()} once you are done with the * broadcast. This allows you to process the broadcast off of the main * thread of your app. * * <p>Note on threading: the state inside of this class is not itself * thread-safe, however you can use it from any thread if you properly * sure that you do not have races. Typically this means you will hand * the entire object to another thread, which will be solely responsible * for setting any results and finally calling {@link #finish()}. */ public static class PendingResult { //.... /** * Finish the broadcast. The current result will be sent and the * next broadcast will proceed. */ public final void finish() { if (mType == TYPE_COMPONENT) { final IActivityManager mgr = ActivityManagerNative.getDefault(); if (QueuedWork.hasPendingWork()) { // If this is a broadcast component, we need to make sure any // queued work is complete before telling AM we are done, so // we don't have our process killed before that. We now know // there is pending work; put another piece of work at the end // of the list to finish the broadcast, so we don't block this // thread (which may be the main thread) to have it finished. // // Note that we don't need to use QueuedWork.add() with the // runnable, since we know the AM is waiting for us until the // executor gets to it. QueuedWork.singleThreadExecutor().execute( new Runnable() { @Override public void run() { if (ActivityThread.DEBUG_BROADCAST) Slog.i(ActivityThread.TAG, "Finishing broadcast after work to component " + mToken); sendFinished(mgr); } }); } else { if (ActivityThread.DEBUG_BROADCAST) Slog.i(ActivityThread.TAG, "Finishing broadcast to component " + mToken); sendFinished(mgr); } } else if (mOrderedHint && mType != TYPE_UNREGISTERED) { if (ActivityThread.DEBUG_BROADCAST) Slog.i(ActivityThread.TAG, "Finishing broadcast to " + mToken); final IActivityManager mgr = ActivityManagerNative.getDefault(); sendFinished(mgr); } } /** @hide */ public void sendFinished(IActivityManager am) { synchronized (this) { if (mFinished) { throw new IllegalStateException("Broadcast already finished"); } mFinished = true; try { if (mResultExtras != null) { mResultExtras.setAllowFds(false); } if (mOrderedHint) { am.finishReceiver(mToken, mResultCode, mResultData, mResultExtras, mAbortBroadcast, mFlags); } else { // This broadcast was sent to a component; it is not ordered, // but we still need to tell the activity manager we are done. am.finishReceiver(mToken, 0, null, null, false, mFlags); } } catch (RemoteException ex) { } } } } }frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java public void finishReceiver(IBinder who, int resultCode, String resultData, Bundle resultExtras, boolean resultAbort, int flags) { if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Finish receiver: " + who); // Refuse possible leaked file descriptors if (resultExtras != null && resultExtras.hasFileDescriptors()) { throw new IllegalArgumentException("File descriptors passed in Bundle"); } final long origId = Binder.clearCallingIdentity(); try { boolean doNext = false; BroadcastRecord r; synchronized(this) { BroadcastQueue queue = (flags & Intent.FLAG_RECEIVER_FOREGROUND) != 0 ? mFgBroadcastQueue : mBgBroadcastQueue; r = queue.getMatchingOrderedReceiver(who); if (r != null) { doNext = r.queue.finishReceiverLocked(r, resultCode, resultData, resultExtras, resultAbort, true); } } if (doNext) { r.queue.processNextBroadcast(false);//处理下一个 } trimApplications(); } finally { Binder.restoreCallingIdentity(origId); } }最终调回BroadcastQueue.processNextBroadcast继续执行发送下一个广播(BOOT_COMPLETED).为什么跟QuickSearchBox有关, 在代码中加了LOG://diff --git a/packages/apps/QuickSearchBox/src/com/android/quicksearchbox/SearchWidgetProvider.java b/packages/apps/QuickSearchBox/src/com/android/quicksearchbox/SearchWidgetProvider.java //old mode 100644 //new mode 100755 index 205e7cc..4ee4dbb --- a/packages/apps/QuickSearchBox/src/com/android/quicksearchbox/SearchWidgetProvider.java +++ b/packages/apps/QuickSearchBox/src/com/android/quicksearchbox/SearchWidgetProvider.java @@ -51,7 +51,7 @@ import java.util.Random; */ public class SearchWidgetProvider extends BroadcastReceiver { - private static final boolean DBG = false; + private static final boolean DBG = true; private static final String TAG = "QSB.SearchWidgetProvider"; /**/ @@ -73,12 +73,15 @@ public class SearchWidgetProvider extends BroadcastReceiver { } private static SearchWidgetState[] getSearchWidgetStates(Context context) { + if (DBG) Log.d(TAG, "getSearchWidgetStates"); AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context); int[] appWidgetIds = appWidgetManager.getAppWidgetIds(myComponentName(context)); + if (DBG) Log.d(TAG, "getSearchWidgetStates appWidgetManager.getAppWidgetIds [F]"); SearchWidgetState[] states = new SearchWidgetState[appWidgetIds.length]; for (int i = 0; i<appWidgetIds.length; ++i) { states[i] = getSearchWidgetState(context, appWidgetIds[i]); } + if (DBG) Log.d(TAG, "getSearchWidgetStates finish"); return states; } @@ -93,6 +96,7 @@ public class SearchWidgetProvider extends BroadcastReceiver { for (SearchWidgetState state : states) { state.updateWidget(context, AppWidgetManager.getInstance(context)); } + if (DBG) Log.d(TAG, "updateSearchWidgets finish"); } /**输出的LOG01-18 17:02:21.106 D/QSB.SearchWidgetProvider( 1154): onReceive(#Intent;action=android.appwidget.action.APPWIDGET_UPDATE;launchFlags=0x10;component=com.android.quicksearchbox/.SearchWidgetProvider;end) 01-18 17:02:21.106 D/QSB.SearchWidgetProvider( 1154): updateSearchWidgets 01-18 17:02:21.106 D/QSB.SearchWidgetProvider( 1154): getSearchWidgetStates 01-18 17:02:21.114 D/QSB.SearchWidgetProvider( 1154): getSearchWidgetStates appWidgetManager.getAppWidgetIds [F] 01-18 17:02:21.114 D/QSB.SearchWidgetProvider( 1154): Creating appwidget state 11960 //省略 N 行 01-18 17:02:28.723 D/QSB.SearchWidgetProvider( 1154): Creating appwidget state 11962 01-18 17:02:28.724 D/QSB.SearchWidgetProvider( 1154): getSearchWidgetStates finish 01-18 17:02:28.724 D/QSB.SearchWidgetProvider( 1154): Updating appwidget 11960 //省略 N 行 01-18 17:02:59.096 D/QSB.SearchWidgetProvider( 1154): Updating appwidget 9262 01-18 17:03:04.446 D/QSB.SearchWidgetProvider( 1154): updateSearchWidgets finish**int[] appWidgetIds = appWidgetManager.getAppWidgetIds(myComponentName(context));**返回了很多ID而这个ID则由系统服务维护处理:frameworks/base/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java具体不细讲, 这些ID保存在/data下的一个文件: system/users/0/appwidgets.xml罪魁祸首问题的症结在于 appwidgets.xml 中的内容会每重启一次自增一行. 如:第一次启动内容<?xml version='1.0' encoding='utf-8' standalone='yes' ?> <gs version="1"> <p pkg="com.android.deskclock" cl="com.android.alarmclock.AnalogAppWidgetProvider" tag="2" /> <p pkg="com.android.quicksearchbox" cl="com.android.quicksearchbox.SearchWidgetProvider" tag="7" /> <h pkg="com.android.launcher3" id="400" tag="0" /> <g id="2ebc" rid="0" h="0" p="7" min_width="3a2" min_height="ae" max_width="672" max_height="ce" host_category="1" /> <g id="2ebe" rid="0" h="0" p="2" min_width="11e" min_height="144" max_width="20e" max_height="184" host_category="1" /> <g id="2ec0" rid="0" h="0" p="7" min_width="3a2" min_height="ae" max_width="672" max_height="ce" host_category="1" /> </gs>第二次启动内容<?xml version='1.0' encoding='utf-8' standalone='yes' ?> <gs version="1"> <!-- 小部件的描述, 如组件信息包类名等 --> <p pkg="com.android.deskclock" cl="com.android.alarmclock.AnalogAppWidgetProvider" tag="2" /> <p pkg="com.android.quicksearchbox" cl="com.android.quicksearchbox.SearchWidgetProvider" tag="7" /> <!-- 持有者信息, 如当前是Launcher3中调用显示了小部件 --> <h pkg="com.android.launcher3" id="400" tag="0" /> <!-- 小部件信息, id, 长宽, 持有者等 --> <g id="2ec0" rid="0" h="0" p="7" min_width="3a2" min_height="ae" max_width="672" max_height="ce" host_category="1" /> <g id="2ebe" rid="0" h="0" p="2" min_width="11e" min_height="144" max_width="20e" max_height="184" host_category="1" /> <g id="2ebc" rid="0" h="0" p="7" min_width="3a2" min_height="ae" max_width="672" max_height="ce" host_category="1" /> <g id="2ec2" rid="0" h="0" p="7" min_width="3a2" min_height="ae" max_width="672" max_height="ce" host_category="1" /> </gs>当前重启了5000+后, cat system/users/0/appwidgets.xml<?xml version='1.0' encoding='utf-8' standalone='yes' ?> <gs version="1"> <p pkg="com.android.quicksearchbox" cl="com.android.quicksearchbox.SearchWidgetProvider" tag="7" /> <h pkg="com.android.launcher3" id="400" tag="0" /> <g id="22c8" rid="0" h="0" p="7" min_width="3a2" min_height="ae" max_width="672" max_height="ce" host_category="1" /> <!-- 此处省略5000行 --> </gs>在后续测试中, 发现, 手动往Launcher3添加时钟小部件, 不管重启几次都不会自增一行, 而搜索的小部件, 是由Launcher3自动添进去的, 它是个特殊的存在于是, 查了下Launcher3的layout如图:packages/apps/Launcher3/src/com/android/launcher3/QsbContainerView.java private View createQsb(LayoutInflater inflater, ViewGroup container) { Launcher launcher = Launcher.getLauncher(getActivity()); mWidgetInfo = getSearchWidgetProvider(launcher); if (mWidgetInfo == null) { // There is no search provider, just show the default widget. return getDefaultView(inflater, container, false); } SharedPreferences prefs = Utilities.getPrefs(launcher); AppWidgetManagerCompat widgetManager = AppWidgetManagerCompat.getInstance(launcher); LauncherAppWidgetHost widgetHost = launcher.getAppWidgetHost(); InvariantDeviceProfile idp = LauncherAppState.getInstance().getInvariantDeviceProfile(); Bundle opts = new Bundle(); Rect size = AppWidgetResizeFrame.getWidgetSizeRanges(launcher, idp.numColumns, 1, null); opts.putInt(AppWidgetManager.OPTION_APPWIDGET_MIN_WIDTH, size.left); opts.putInt(AppWidgetManager.OPTION_APPWIDGET_MIN_HEIGHT, size.top); opts.putInt(AppWidgetManager.OPTION_APPWIDGET_MAX_WIDTH, size.right); opts.putInt(AppWidgetManager.OPTION_APPWIDGET_MAX_HEIGHT, size.bottom); int widgetId = prefs.getInt(QSB_WIDGET_ID, -1); AppWidgetProviderInfo widgetInfo = widgetManager.getAppWidgetInfo(widgetId); boolean isWidgetBound = (widgetInfo != null) && widgetInfo.provider.equals(mWidgetInfo.provider); if (!isWidgetBound) { // widgetId is already bound and its not the correct provider. // Delete the widget id. if (widgetId > -1) { widgetHost.deleteAppWidgetId(widgetId); widgetId = -1; } widgetId = widgetHost.allocateAppWidgetId(); isWidgetBound = widgetManager.bindAppWidgetIdSkipBindPermission(widgetId, mWidgetInfo, opts); if (!isWidgetBound) { widgetHost.deleteAppWidgetId(widgetId); widgetId = -1; } } if (isWidgetBound) { mQsb = (LauncherAppWidgetHostView) widgetHost.createView(launcher, widgetId, mWidgetInfo); mQsb.setId(R.id.qsb_widget); mQsb.mErrorViewId = R.layout.qsb_default_view; if (!Utilities.containsAll(AppWidgetManager.getInstance(launcher) .getAppWidgetOptions(widgetId), opts)) { try{ mQsb.updateAppWidgetOptions(opts); }catch(Exception e){ Log.v("QsbContainerView", "getQsbBar error "+e.getMessage()); return null; } } mQsb.setPadding(0, 0, 0, 0); return mQsb; } // Return a default widget with setup icon. return getDefaultView(inflater, container, true); }这段代码的问题在于int widgetId = prefs.getInt(QSB_WIDGET_ID, -1);, widgetId一直是 -1.widgetId = widgetHost.allocateAppWidgetId();申请了一个ID, 并调用bindAppWidgetIdSkipBindPermission, 在这个操作完成后, system/users/0/appwidgets.xml 就增加了一行.而后, 在SearchWidgetProvider就得处理多一次, 在几千次后, 时间就不是那么容易忽略的问题了.后话这个问题在RK3288上面也同样存在
平台Android 7.1 + RK3288环境当前的签名文件如下:build/target/product/security/ -rw-rw-r-- 1 anson anson 260 6月 19 2018 Android.mk -rw-rw-r-- 1 anson anson 1675 6月 19 2018 media.pem -rw-rw-r-- 1 anson anson 1217 6月 19 2018 media.pk8 -rw-rw-r-- 1 anson anson 1440 6月 19 2018 media.x509.pem -rw-rw-r-- 1 anson anson 1675 6月 19 2018 platform.pem -rw-rw-r-- 1 anson anson 1216 6月 19 2018 platform.pk8 -rw-rw-r-- 1 anson anson 1440 6月 19 2018 platform.x509.pem -rw-rw-r-- 1 anson anson 3123 6月 19 2018 README -rw-rw-r-- 1 anson anson 1679 6月 19 2018 shared.pem -rw-rw-r-- 1 anson anson 1218 6月 19 2018 shared.pk8 -rw-rw-r-- 1 anson anson 1440 6月 19 2018 shared.x509.pem -rw-rw-r-- 1 anson anson 1675 6月 19 2018 testkey.pem -rw-rw-r-- 1 anson anson 1216 6月 19 2018 testkey.pk8 -rw-rw-r-- 1 anson anson 1440 6月 19 2018 testkey.x509.pem -rw-rw-r-- 1 anson anson 524 6月 19 2018 verity_key -rw-rw-r-- 1 anson anson 1219 6月 19 2018 verity.pk8 -rw-rw-r-- 1 anson anson 1444 6月 19 2018 verity.x509.pem对应的几个密钥的用途:testkey # 普通APK,默认情况下使用 platform # 该APK完成一些系统的核心功能,这种方式编译出来的APK所在进程的UID为system shared # 该APK是media/download系统中的一环 media # 该APK是media/download系统中的一环build/core/main.mk include $(BUILD_SYSTEM)/config.mkbuild/core/config.mk include $(BUILD_SYSTEM)/envsetup.mk DEFAULT_SYSTEM_DEV_CERTIFICATE := build/target/product/security/testkeytestkey 不仅会影响应用的签名, 同时还有打包的固件OTA升级包等.实现最简单的方案, 替换掉 build/target/product/security 相关的密钥文件自定义密钥名, 同时修改Makefile 和 相应的.MK文件build/core/config.mk: 中DEFAULT_SYSTEM_DEV_CERTIFICATE := build/target/product/security/mykeybuild/core/Makefile: ifeq ($(DEFAULT_SYSTEM_DEV_CERTIFICATE),build/target/product/security/mykey)关于apk签名,可通过修改Android.mk中的声明修改签名:LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE_TAGS := optional LOCAL_SRC_FILES := $(call all-subdir-java-files) LOCAL_PACKAGE_NAME := Provision LOCAL_CERTIFICATE := mykey ## 也可定义绝对路径: #LOCAL_CERTIFICATE := build/target/product/security/mykey/mykey LOCAL_PRIVILEGED_MODULE := true LOCAL_PROGUARD_FLAG_FILES := proguard.flags include $(BUILD_PACKAGE)确认build/target/product/security/mykey相关文件存在, 否则会出现:ninja: error: 'build/target/product/security/mykey.pk8', needed by 'out/target/product/rk3288/obj/APPS/Provision_intermediates/package.apk', missing and no known rule to make itbuild/core/package_internal.mk# Pick a key to sign the package with. If this package hasn't specified # an explicit certificate, use the default. # Secure release builds will have their packages signed after the fact, # so it's ok for these private keys to be in the clear. ifeq ($(LOCAL_CERTIFICATE),) LOCAL_CERTIFICATE := $(DEFAULT_SYSTEM_DEV_CERTIFICATE) endif ifeq ($(LOCAL_CERTIFICATE),EXTERNAL) # The special value "EXTERNAL" means that we will sign it with the # default devkey, apply predexopt, but then expect the final .apk # (after dexopting) to be signed by an outside tool. LOCAL_CERTIFICATE := $(DEFAULT_SYSTEM_DEV_CERTIFICATE) PACKAGES.$(LOCAL_PACKAGE_NAME).EXTERNAL_KEY := 1 endif # If this is not an absolute certificate, assign it to a generic one. ifeq ($(dir $(strip $(LOCAL_CERTIFICATE))),./) LOCAL_CERTIFICATE := $(dir $(DEFAULT_SYSTEM_DEV_CERTIFICATE))$(LOCAL_CERTIFICATE) endif private_key := $(LOCAL_CERTIFICATE).pk8 certificate := $(LOCAL_CERTIFICATE).x509.pem从生成的中间ninja->out/build-rk3288-mmm-packages_apps_Provision_Android.mk.ninjadescription = target Package: Provision (out/target/product/rk3288/obj/APPS/Provision_intermediates/package.apk) command = /bin/bash -c "(touch out/target/product/rk3288/obj/APPS/Provision_intermediates/zipdummy ) && ((cd out/target/product/rk3288/obj/APPS/Provision_intermediates/ && jar cf package.apk zipdummy) ) && (zip -qd out/target/product/rk3288/obj/APPS/Provision_intermediates/package.apk zipdummy ) && (rm out/target/product/rk3288/obj/APPS/Provision_intermediates/zipdummy ) && (out/host/linux-x86/bin/aapt package -u -z --pseudo-localize -c zh_CN,en_US,cs_CZ,da_DK,de_AT,de_CH,de_DE,de_LI,el_GR,en_AU,en_CA,en_GB,en_NZ,en_SG,eo_EU,es_ES,fr_CA,fr_CH,fr_BE,fr_FR,it_CH,it_IT,ja_JP,ko_KR,nb_NO,nl_BE,nl_NL,pl_PL,pt_PT,ru_RU,sv_SE,tr_TR,zh_CN,zh_HK,zh_TW,am_ET,hi_IN,en_US,en_AU,en_IN,fr_FR,it_IT,es_ES,et_EE,de_DE,nl_NL,cs_CZ,pl_PL,ja_JP,zh_TW,zh_CN,zh_HK,ru_RU,ko_KR,nb_NO,es_US,da_DK,el_GR,tr_TR,pt_PT,pt_BR,sv_SE,bg_BG,ca_ES,en_GB,fi_FI,hi_IN,hr_HR,hu_HU,in_ID,iw_IL,lt_LT,lv_LV,ro_RO,sk_SK,sl_SI,sr_RS,uk_UA,vi_VN,tl_PH,ar_EG,fa_IR,th_TH,sw_TZ,ms_MY,af_ZA,zu_ZA,am_ET,en_XA,ar_XB,fr_CA,km_KH,lo_LA,ne_NP,si_LK,mn_MN,hy_AM,az_AZ,ka_GE,my_MM,mr_IN,ml_IN,is_IS,mk_MK,ky_KG,eu_ES,gl_ES,bn_BD,ta_IN,kn_IN,te_IN,uz_UZ,ur_PK,kk_KZ,sq_AL,gu_IN,pa_IN,be_BY,bs_BA -M packages/apps/Provision/AndroidManifest.xml -I out/target/common/obj/APPS/framework-res_intermediates/package-export.apk --min-sdk-version 25 --target-sdk-version 25 --product tablet --version-code 25 --version-name 7.1.2 --skip-symbols-without-default-localization -F out/target/product/rk3288/obj/APPS/Provision_intermediates/package.apk ) && (find out/target/common/obj/APPS/Provision_intermediates/ -maxdepth 1 -name \"classes*.dex\" | sort | xargs zip -qjX out/target/product/rk3288/obj/APPS/Provision_intermediates/package.apk ) && (if [ -d out/target/common/obj/APPS/Provision_intermediates/jack-rsc ] ; then find out/target/common/obj/APPS/Provision_intermediates/jack-rsc -type f | sort | sed -e \"s?^out/target/common/obj/APPS/Provision_intermediates/jack-rsc/? -C \\\"out/target/common/obj/APPS/Provision_intermediates/jack-rsc\\\" \\\"?\" -e \"s/\$$/\\\"/\" > out/target/product/rk3288/obj/APPS/Provision_intermediates/jack_res_jar_flags; if [ -s out/target/product/rk3288/obj/APPS/Provision_intermediates/jack_res_jar_flags ] ; then jar uf out/target/product/rk3288/obj/APPS/Provision_intermediates/package.apk @out/target/product/rk3288/obj/APPS/Provision_intermediates/jack_res_jar_flags; fi; fi ) && (mv out/target/product/rk3288/obj/APPS/Provision_intermediates/package.apk out/target/product/rk3288/obj/APPS/Provision_intermediates/package.apk.unsigned ) && (java -Djava.library.path=out/host/linux-x86/lib64 -jar out/host/linux-x86/framework/signapk.jar --min-sdk-version \ $$((out/host/linux-x86/bin/aapt dump badging out/target/product/rk3288/obj/APPS/Provision_intermediates/package.apk.unsigned 2>&1 | grep '^sdkVersion' || echo \"sdkVersion:'0'\") | cut -d\"'\" -f2 | sed -e s/^.*[^0-9].*\$$/25/) build/target/product/security/mykey.x509.pem build/target/product/security/mykey.pk8 out/target/product/rk3288/obj/APPS/Provision_intermediates/package.apk.unsigned out/target/product/rk3288/obj/APPS/Provision_intermediates/package.apk.signed ) && (mv out/target/product/rk3288/obj/APPS/Provision_intermediates/package.apk.signed out/target/product/rk3288/obj/APPS/Provision_intermediates/package.apk )"可以看出, 编译系统会去找build/target/product/security/mykey.x509.pem, build/target/product/security/mykey.pk8扩展android系统release签名Android OTA releasekey 替换Android系统build阶段签名机制Manually generating keys 创建密钥方法1:development/tools/make_key testkey '/C=US/ST=California/L=Mountain View/O=Android/OU=Android/CN=Android/emailAddress=android@android.com'方法2:# generate RSA key openssl genrsa -3 -out temp.pem 2048 Generating RSA private key, 2048 bit long modulus ....+++ .....................+++ e is 3 (0x3) # create a certificate with the public part of the key openssl req -new -x509 -key temp.pem -out releasekey.x509.pem -days 10000 -subj '/C=US/ST=California/L=San Narciso/O=Yoyodyne, Inc./OU=Yoyodyne Mobility/CN=Yoyodyne/emailAddress=yoyodyne@example.com' # create a PKCS#8-formatted version of the private key openssl pkcs8 -in temp.pem -topk8 -outform DER -out releasekey.pk8 -nocrypt # securely delete the temp.pem file shred --remove temp.pemAndroid签名生成和互转打印编译时的环境变量:build/core/dumpvar.mk print_build_config_vars := \ PLATFORM_VERSION_CODENAME \ PLATFORM_VERSION \ TARGET_PRODUCT \ TARGET_BUILD_VARIANT \ TARGET_BUILD_TYPE \ TARGET_BUILD_APPS \ TARGET_ARCH \ TARGET_ARCH_VARIANT \ TARGET_CPU_VARIANT \ TARGET_2ND_ARCH \ TARGET_2ND_ARCH_VARIANT \ TARGET_2ND_CPU_VARIANT \ HOST_ARCH \ HOST_2ND_ARCH \ HOST_OS \ HOST_OS_EXTRA \ HOST_CROSS_OS \ HOST_CROSS_ARCH \ HOST_CROSS_2ND_ARCH \ HOST_BUILD_TYPE \ BUILD_ID \ OUT_DIR ifneq ($(filter report_config,$(DUMP_MANY_VARS)),) # Construct the shell commands that print the config banner. report_config_sh := echo '============================================'; report_config_sh += $(foreach v,$(print_build_config_vars),echo '$v=$($(v))';) report_config_sh += echo '============================================'; endif============================================ PLATFORM_VERSION_CODENAME=REL PLATFORM_VERSION=7.1.2 TARGET_PRODUCT=rk3288 TARGET_BUILD_VARIANT=userdebug TARGET_BUILD_TYPE=release TARGET_BUILD_APPS= TARGET_ARCH=arm TARGET_ARCH_VARIANT=armv7-a-neon TARGET_CPU_VARIANT=cortex-a15 TARGET_2ND_ARCH= TARGET_2ND_ARCH_VARIANT= TARGET_2ND_CPU_VARIANT= HOST_ARCH=x86_64 HOST_2ND_ARCH=x86 HOST_OS=linux HOST_OS_EXTRA=Linux-4.15.0-64-generic-x86_64-with-Ubuntu-16.04-xenial HOST_CROSS_OS=windows HOST_CROSS_ARCH=x86 HOST_CROSS_2ND_ARCH=x86_64 HOST_BUILD_TYPE=release BUILD_ID=NHG47K OUT_DIR=out BUILD_SYSTEM=build/core ============================================build/core/Makefile# The "test-keys" tag marks builds signed with the old test keys, # which are available in the SDK. "dev-keys" marks builds signed with # non-default dev keys (usually private keys from a vendor directory). # Both of these tags will be removed and replaced with "release-keys" # when the target-files is signed in a post-build step. ifeq ($(DEFAULT_SYSTEM_DEV_CERTIFICATE),build/target/product/security/testkey) BUILD_KEYS := test-keys else BUILD_KEYS := dev-keys endif ifeq ($(TARGET_BUILD_VARIANT),user) BUILD_KEYS := release-keys endif判断编译所使用的密钥, 并会显示设置 > 关于设备 > 版本号末尾, 如:XXX-userdebug 7.1.2 NHG47K eng.XXX.20191125.144140 test-keys
平台RK3288 + Android 7.1问题描述安装Launcher应用, 并设置为默认主界面, 关机重启后, 无法默认, 仍然弹出选择框.分析LOG//开机后启动的第一个HOME, 是FallbackHome 2019-11-22 15:11:25.542 system_process I/ActivityManager: START u0 {act=android.intent.action.MAIN cat=[android.intent.category.HOME] flg=0x10000100 cmp=com.android.settings/.FallbackHome} from uid 0 on display 0 2019-11-22 15:11:25.565 system_process I/ActivityManager: Start proc 650:com.android.settings/1000 for activity com.android.settings/.FallbackHome 2019-11-22 15:11:26.158 system_process I/ActivityManager: Displayed com.android.settings/.FallbackHome: +604ms //... 2019-11-22 15:11:27.976 system_process D/ActivityManager: Sending BOOT_COMPLETE user #0 //... 2019-11-22 15:11:28.007 system_process V/PackageManager: Looking for presistent preferred activities... 2019-11-22 15:11:28.007 system_process V/PackageManager: Looking for preferred activities... 2019-11-22 15:11:28.007 system_process V/IntentResolver: Resolving type=null scheme=null defaultOnly=false userId=0 of Intent { act=android.intent.action.MAIN cat=[android.intent.category.HOME] flg=0x8 } 2019-11-22 15:11:28.007 system_process V/IntentResolver: Action list: [PreferredActivity{0xa4a6978 com.teslacoilsw.launcher/.NovaLauncher}, null] 2019-11-22 15:11:28.008 system_process V/IntentResolver: Matching against filter PreferredActivity{0xa4a6978 com.teslacoilsw.launcher/.NovaLauncher} 2019-11-22 15:11:28.008 system_process V/IntentResolver: Filter matched! match=0x108000 hasDefault=true 2019-11-22 15:11:28.008 system_process V/IntentResolver: a4a6978 com.teslacoilsw.launcher/.NovaLauncher 2019-11-22 15:11:28.008 system_process V/IntentResolver: mMatch=0x100000 mAlways=true 2019-11-22 15:11:28.008 system_process V/IntentResolver: Selected from: 2019-11-22 15:11:28.008 system_process V/IntentResolver: com.android.launcher3/.Launcher 2019-11-22 15:11:28.008 system_process V/IntentResolver: com.teslacoilsw.launcher/.NovaLauncher 2019-11-22 15:11:28.008 system_process V/IntentResolver: com.android.settings/.FallbackHome 2019-11-22 15:11:28.008 system_process V/IntentResolver: Action: "android.intent.action.MAIN" 2019-11-22 15:11:28.008 system_process V/IntentResolver: Category: "android.intent.category.HOME" 2019-11-22 15:11:28.008 system_process V/IntentResolver: Category: "android.intent.category.DEFAULT" 2019-11-22 15:11:28.008 system_process V/IntentResolver: AutoVerify=false 2019-11-22 15:11:28.008 system_process V/IntentResolver: Final result list: 2019-11-22 15:11:28.008 system_process V/IntentResolver: PreferredActivity{0xa4a6978 com.teslacoilsw.launcher/.NovaLauncher} 2019-11-22 15:11:28.008 system_process V/PackageManager: Figuring out best match... 2019-11-22 15:11:28.008 system_process V/PackageManager: Match for ActivityInfo{2bec482 com.android.launcher3.Launcher}: 0x0 2019-11-22 15:11:28.008 system_process V/PackageManager: Match for ActivityInfo{9a57793 com.teslacoilsw.launcher.NovaLauncher}: 0x108000 2019-11-22 15:11:28.008 system_process V/PackageManager: Match for ActivityInfo{494e3d0 teaonly.rk.droidipcam.CameraActivity}: 0x108000 2019-11-22 15:11:28.008 system_process V/PackageManager: Match for ActivityInfo{3ae8fc9 com.android.settings.FallbackHome}: 0x108000 2019-11-22 15:11:28.011 system_process V/PackageManager: Best match: 0x108000 2019-11-22 15:11:28.011 system_process V/PackageManager: Checking PreferredActivity ds=<none> component=ComponentInfo{com.teslacoilsw.launcher/com.teslacoilsw.launcher.NovaLauncher} 2019-11-22 15:11:28.011 system_process V/PackageManager: Action: "android.intent.action.MAIN" 2019-11-22 15:11:28.011 system_process V/PackageManager: Category: "android.intent.category.HOME" 2019-11-22 15:11:28.011 system_process V/PackageManager: Category: "android.intent.category.DEFAULT" 2019-11-22 15:11:28.011 system_process V/PackageManager: AutoVerify=false 2019-11-22 15:11:28.011 system_process V/PackageManager: Found preferred activity: 2019-11-22 15:11:28.011 system_process V/PackageManager: name=com.teslacoilsw.launcher.NovaLauncher 2019-11-22 15:11:28.011 system_process V/PackageManager: packageName=com.teslacoilsw.launcher 2019-11-22 15:11:28.011 system_process V/PackageManager: enabled=true exported=true directBootAware=false 2019-11-22 15:11:28.011 system_process V/PackageManager: taskAffinity=com.teslacoilsw.launcher.NovaLauncher targetActivity=null persistableMode=PERSIST_ROOT_ONLY 2019-11-22 15:11:28.011 system_process V/PackageManager: launchMode=3 flags=0x3 theme=0x7f0d00f2 2019-11-22 15:11:28.011 system_process V/PackageManager: screenOrientation=5 configChanges=0x203 softInputMode=0x20 2019-11-22 15:11:28.011 system_process V/PackageManager: lockTaskLaunchMode=LOCK_TASK_LAUNCH_MODE_DEFAULT 2019-11-22 15:11:28.011 system_process V/PackageManager: resizeMode=RESIZE_MODE_RESIZEABLE 2019-11-22 15:11:28.011 system_process V/PackageManager: ApplicationInfo: 2019-11-22 15:11:28.011 system_process V/PackageManager: name=com.android.launcher3.LauncherApplication 2019-11-22 15:11:28.011 system_process V/PackageManager: packageName=com.teslacoilsw.launcher 2019-11-22 15:11:28.011 system_process V/PackageManager: labelRes=0x7f0a0060 nonLocalizedLabel=null icon=0x7f030008 banner=0x0 2019-11-22 15:11:28.011 system_process V/PackageManager: className=com.android.launcher3.LauncherApplication 2019-11-22 15:11:28.011 system_process V/PackageManager: processName=com.teslacoilsw.launcher 2019-11-22 15:11:28.011 system_process V/PackageManager: taskAffinity=com.teslacoilsw.launcher 2019-11-22 15:11:28.011 system_process V/PackageManager: uid=10054 flags=0x3 privateFlags=0x800 theme=0x0 2019-11-22 15:11:28.011 system_process V/PackageManager: requiresSmallestWidthDp=0 compatibleWidthLimitDp=0 largestWidthLimitDp=0 2019-11-22 15:11:28.012 system_process V/PackageManager: sourceDir=/data/app/com.teslacoilsw.launcher-1/base.apk 2019-11-22 15:11:28.012 system_process V/PackageManager: seinfo=default 2019-11-22 15:11:28.012 system_process V/PackageManager: dataDir=/data/user/0/com.teslacoilsw.launcher 2019-11-22 15:11:28.012 system_process V/PackageManager: deviceProtectedDataDir=/data/user_de/0/com.teslacoilsw.launcher 2019-11-22 15:11:28.012 system_process V/PackageManager: credentialProtectedDataDir=/data/user/0/com.teslacoilsw.launcher 2019-11-22 15:11:28.012 system_process V/PackageManager: enabled=true minSdkVersion=16 targetSdkVersion=25 versionCode=50102 2019-11-22 15:11:28.012 system_process V/PackageManager: supportsRtl=true 2019-11-22 15:11:28.012 system_process V/PackageManager: fullBackupContent=true //关键LOG, 这里把默认信息删除了. 2019-11-22 15:11:28.012 system_process I/PackageManager: Result set changed, dropping preferred activity for Intent { act=android.intent.action.MAIN cat=[android.intent.category.HOME] flg=0x8 } type null 2019-11-22 15:11:28.012 system_process V/PackageManager: Removing preferred activity since set changed ComponentInfo{com.teslacoilsw.launcher/com.teslacoilsw.launcher.NovaLauncher} 2019-11-22 15:11:28.012 system_process V/PackageManager: Preferred activity bookkeeping changed; writing restrictions 2019-11-22 15:11:28.013 com.android.settings D/FallbackHome: User unlocked and real home found; let's go! //再一次查找HOME时, 发现没有了默认信息, 所以显示了选择提示框 2019-11-22 15:11:28.049 system_process I/AccountManagerService: User 0 is unlocked - opening CE database 2019-11-22 15:11:28.056 system_process V/PackageManager: Looking for presistent preferred activities... 2019-11-22 15:11:28.056 system_process V/PackageManager: Looking for preferred activities... 2019-11-22 15:11:28.057 system_process V/IntentResolver: Resolving type=null scheme=null defaultOnly=false userId=0 of Intent { act=android.intent.action.MAIN cat=[android.intent.category.HOME] flg=0x108 } 2019-11-22 15:11:28.057 system_process V/IntentResolver: Action list: [PreferredActivity{0xf98a6ce com.teslacoilsw.launcher/.NovaLauncher}, null] 2019-11-22 15:11:28.057 system_process V/IntentResolver: Matching against filter PreferredActivity{0xf98a6ce com.teslacoilsw.launcher/.NovaLauncher} 2019-11-22 15:11:28.057 system_process V/IntentResolver: Filter matched! match=0x108000 hasDefault=true 2019-11-22 15:11:28.057 system_process V/IntentResolver: f98a6ce com.teslacoilsw.launcher/.NovaLauncher 2019-11-22 15:11:28.057 system_process V/IntentResolver: mMatch=0x100000 mAlways=false 2019-11-22 15:11:28.057 system_process V/IntentResolver: Action: "android.intent.action.MAIN" 2019-11-22 15:11:28.057 system_process V/IntentResolver: Category: "android.intent.category.HOME" 2019-11-22 15:11:28.057 system_process V/IntentResolver: Category: "android.intent.category.DEFAULT" 2019-11-22 15:11:28.057 system_process V/IntentResolver: AutoVerify=false 2019-11-22 15:11:28.057 system_process V/IntentResolver: Final result list: 2019-11-22 15:11:28.057 system_process V/IntentResolver: PreferredActivity{0xf98a6ce com.teslacoilsw.launcher/.NovaLauncher} 2019-11-22 15:11:28.057 system_process V/PackageManager: Figuring out best match... 2019-11-22 15:11:28.057 system_process V/PackageManager: Match for ActivityInfo{2bec482 com.android.launcher3.Launcher}: 0x0 2019-11-22 15:11:28.057 system_process V/PackageManager: Match for ActivityInfo{9a57793 com.teslacoilsw.launcher.NovaLauncher}: 0x108000 2019-11-22 15:11:28.057 system_process V/PackageManager: Match for ActivityInfo{494e3d0 teaonly.rk.droidipcam.CameraActivity}: 0x108000 2019-11-22 15:11:28.057 system_process V/PackageManager: Match for ActivityInfo{3ae8fc9 com.android.settings.FallbackHome}: 0x108000 2019-11-22 15:11:28.057 system_process V/PackageManager: Best match: 0x108000 2019-11-22 15:11:28.057 system_process V/PackageManager: Checking PreferredActivity ds=<none> component=ComponentInfo{com.teslacoilsw.launcher/com.teslacoilsw.launcher.NovaLauncher} 2019-11-22 15:11:28.057 system_process V/PackageManager: Action: "android.intent.action.MAIN" 2019-11-22 15:11:28.057 system_process V/PackageManager: Category: "android.intent.category.HOME" 2019-11-22 15:11:28.057 system_process V/PackageManager: Category: "android.intent.category.DEFAULT" 2019-11-22 15:11:28.057 system_process V/PackageManager: AutoVerify=false 2019-11-22 15:11:28.058 system_process V/PackageManager: Skipping mAlways=false entry 2019-11-22 15:11:28.058 system_process V/PackageManager: No preferred activity to return 2019-11-22 15:11:28.058 system_process I/ActivityManager: START u0 {act=android.intent.action.MAIN cat=[android.intent.category.HOME] flg=0x10000108 cmp=android/com.android.internal.app.ResolverActivity} from uid 0 on display 0 2019-11-22 15:11:28.058 system_process V/IntentResolver: Resolving type=null scheme=null defaultOnly=false userId=0 of Intent { act=android.intent.action.MAIN cat=[android.intent.category.HOME] flg=0x10000108 cmp=android/com.android.internal.app.ResolverActivity } 2019-11-22 15:11:28.058 system_process V/IntentResolver: Action list: null 2019-11-22 15:11:28.058 system_process V/IntentResolver: Final result list: 2019-11-22 15:11:28.090 ? W/System: ClassLoader referenced unknown path: /system/priv-app/StressTest/lib/arm 2019-11-22 15:11:28.098 system_process I/ActivityManager: Start proc 1076:system:ui/1000 for activity android/com.android.internal.app.ResolverActivity开机, 第一次启动:I/ActivityManager: START u0 {act=android.intent.action.MAIN cat=[android.intent.category.HOME,android.intent.category.DEFAULT] flg=0x10000100 cmp=com.android.settings/.FallbackHome} from uid 0 on display 0开机完成第一次, 在退出FallbackHome后:V/IntentResolver: Resolving type=null scheme=null defaultOnly=false userId=0 of Intent { act=android.intent.action.MAIN cat=[android.intent.category.HOME] flg=0x8 } //此时因为缺少了CATEGORY_DEFAULT, 所以PM在查找时, 会找到四个, 分别是: Match for ActivityInfo{2bec482 com.android.launcher3.Launcher}: 0x0 Match for ActivityInfo{9a57793 com.teslacoilsw.launcher.NovaLauncher}: 0x108000 Match for ActivityInfo{494e3d0 teaonly.rk.droidipcam.CameraActivity}: 0x108000 Match for ActivityInfo{3ae8fc9 com.android.settings.FallbackHome}: 0x108000在选择默认时保存的是:2019-11-23 09:02:38.677 system_process I/PackageManager: Adding preferred activity com.teslacoilsw.launcher/.NovaLauncher for user 0: 2019-11-23 09:02:38.677 system_process I/PackageManager: Action: "android.intent.action.MAIN" 2019-11-23 09:02:38.677 system_process I/PackageManager: Category: "android.intent.category.HOME" 2019-11-23 09:02:38.677 system_process I/PackageManager: Category: "android.intent.category.DEFAULT" 2019-11-23 09:02:38.677 system_process I/PackageManager: AutoVerify=false 2019-11-23 09:02:38.679 system_process I/ActivityManager: START u0 {act=android.intent.action.MAIN cat=[android.intent.category.HOME,android.intent.category.DEFAULT] flg=0x13000108 cmp=com.teslacoilsw.launcher/.NovaLauncher} from uid 0 on display 0 2019-11-23 09:02:38.679 system_process V/IntentResolver: Resolving type=null scheme=null defaultOnly=false userId=0 of Intent { act=android.intent.action.MAIN cat=[android.intent.category.HOME,android.intent.category.DEFAULT] flg=0x13000108 cmp=com.teslacoilsw.launcher/.NovaLauncher } 2019-11-23 09:02:38.679 system_process V/IntentResolver: Action list: null 2019-11-23 09:02:38.679 system_process V/IntentResolver: Final result list:相关代码如下:|-- frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java@Override public ResolveInfo resolveIntent(Intent intent, String resolvedType, int flags, int userId) { try { Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "resolveIntent"); if (!sUserManager.exists(userId)) return null; flags = updateFlagsForResolve(flags, userId, intent); enforceCrossUserPermission(Binder.getCallingUid(), userId, false /*requireFullPermission*/, false /*checkShell*/, "resolve intent"); Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "queryIntentActivities"); final List<ResolveInfo> query = queryIntentActivitiesInternal(intent, resolvedType, flags, userId); Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); final ResolveInfo bestChoice = chooseBestActivity(intent, resolvedType, flags, query, userId); return bestChoice; } finally { Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); } } private ResolveInfo chooseBestActivity(Intent intent, String resolvedType, int flags, List<ResolveInfo> query, int userId) { if (query != null) { final int N = query.size(); if (N == 1) { return query.get(0); } else if (N > 1) { final boolean debug = ((intent.getFlags() & Intent.FLAG_DEBUG_LOG_RESOLUTION) != 0); // If there is more than one activity with the same priority, // then let the user decide between them. ResolveInfo r0 = query.get(0); ResolveInfo r1 = query.get(1); if (DEBUG_INTENT_MATCHING || debug) { Slog.v(TAG, r0.activityInfo.name + "=" + r0.priority + " vs " + r1.activityInfo.name + "=" + r1.priority); } // If the first activity has a higher priority, or a different // default, then it is always desirable to pick it. if (r0.priority != r1.priority || r0.preferredOrder != r1.preferredOrder || r0.isDefault != r1.isDefault) { return query.get(0); } // If we have saved a preference for a preferred activity for // this Intent, use that. ResolveInfo ri = findPreferredActivity(intent, resolvedType, flags, query, r0.priority, true, false, debug, userId); if (ri != null) { return ri; } ri = new ResolveInfo(mResolveInfo); ri.activityInfo = new ActivityInfo(ri.activityInfo); ri.activityInfo.labelRes = ResolverActivity.getLabelRes(intent.getAction()); // If all of the options come from the same package, show the application's // label and icon instead of the generic resolver's. // Some calls like Intent.resolveActivityInfo query the ResolveInfo from here // and then throw away the ResolveInfo itself, meaning that the caller loses // the resolvePackageName. Therefore the activityInfo.labelRes above provides // a fallback for this case; we only set the target package's resources on // the ResolveInfo, not the ActivityInfo. final String intentPackage = intent.getPackage(); if (!TextUtils.isEmpty(intentPackage) && allHavePackage(query, intentPackage)) { final ApplicationInfo appi = query.get(0).activityInfo.applicationInfo; ri.resolvePackageName = intentPackage; if (userNeedsBadging(userId)) { ri.noResourceId = true; } else { ri.icon = appi.icon; } ri.iconResourceId = appi.icon; ri.labelRes = appi.labelRes; } ri.activityInfo.applicationInfo = new ApplicationInfo( ri.activityInfo.applicationInfo); if (userId != 0) { ri.activityInfo.applicationInfo.uid = UserHandle.getUid(userId, UserHandle.getAppId(ri.activityInfo.applicationInfo.uid)); } // Make sure that the resolver is displayable in car mode if (ri.activityInfo.metaData == null) ri.activityInfo.metaData = new Bundle(); ri.activityInfo.metaData.putBoolean(Intent.METADATA_DOCK_HOME, true); return ri; } } return null; } ResolveInfo findPreferredActivity(Intent intent, String resolvedType, int flags, List<ResolveInfo> query, int priority, boolean always, boolean removeMatches, boolean debug, int userId) { if (!sUserManager.exists(userId)) return null; flags = updateFlagsForResolve(flags, userId, intent); // writer synchronized (mPackages) { if (intent.getSelector() != null) { intent = intent.getSelector(); } if (DEBUG_PREFERRED) intent.addFlags(Intent.FLAG_DEBUG_LOG_RESOLUTION); // Try to find a matching persistent preferred activity. ResolveInfo pri = findPersistentPreferredActivityLP(intent, resolvedType, flags, query, debug, userId); // If a persistent preferred activity matched, use it. if (pri != null) { return pri; } PreferredIntentResolver pir = mSettings.mPreferredActivities.get(userId); // Get the list of preferred activities that handle the intent if (DEBUG_PREFERRED || debug) Slog.v(TAG, "Looking for preferred activities..."); List<PreferredActivity> prefs = pir != null ? pir.queryIntent(intent, resolvedType, (flags & PackageManager.MATCH_DEFAULT_ONLY) != 0, userId) : null; if (prefs != null && prefs.size() > 0) { boolean changed = false; try { // First figure out how good the original match set is. // We will only allow preferred activities that came // from the same match quality. int match = 0; if (DEBUG_PREFERRED || debug) Slog.v(TAG, "Figuring out best match..."); final int N = query.size(); for (int j=0; j<N; j++) { final ResolveInfo ri = query.get(j); if (DEBUG_PREFERRED || debug) Slog.v(TAG, "Match for " + ri.activityInfo + ": 0x" + Integer.toHexString(match)); if (ri.match > match) { match = ri.match; } } if (DEBUG_PREFERRED || debug) Slog.v(TAG, "Best match: 0x" + Integer.toHexString(match)); match &= IntentFilter.MATCH_CATEGORY_MASK; final int M = prefs.size(); for (int i=0; i<M; i++) { final PreferredActivity pa = prefs.get(i); if (DEBUG_PREFERRED || debug) { Slog.v(TAG, "Checking PreferredActivity ds=" + (pa.countDataSchemes() > 0 ? pa.getDataScheme(0) : "<none>") + "\n component=" + pa.mPref.mComponent); pa.dump(new LogPrinter(Log.VERBOSE, TAG, Log.LOG_ID_SYSTEM), " "); } if (pa.mPref.mMatch != match) { if (DEBUG_PREFERRED || debug) Slog.v(TAG, "Skipping bad match " + Integer.toHexString(pa.mPref.mMatch)); continue; } // If it's not an "always" type preferred activity and that's what we're // looking for, skip it. if (always && !pa.mPref.mAlways) { if (DEBUG_PREFERRED || debug) Slog.v(TAG, "Skipping mAlways=false entry"); continue; } final ActivityInfo ai = getActivityInfo( pa.mPref.mComponent, flags | MATCH_DISABLED_COMPONENTS | MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE, userId); if (DEBUG_PREFERRED || debug) { Slog.v(TAG, "Found preferred activity:"); if (ai != null) { ai.dump(new LogPrinter(Log.VERBOSE, TAG, Log.LOG_ID_SYSTEM), " "); } else { Slog.v(TAG, " null"); } } if (ai == null) { // This previously registered preferred activity // component is no longer known. Most likely an update // to the app was installed and in the new version this // component no longer exists. Clean it up by removing // it from the preferred activities list, and skip it. Slog.w(TAG, "Removing dangling preferred activity: " + pa.mPref.mComponent); pir.removeFilter(pa); changed = true; continue; } for (int j=0; j<N; j++) { final ResolveInfo ri = query.get(j); if (!ri.activityInfo.applicationInfo.packageName .equals(ai.applicationInfo.packageName)) { continue; } if (!ri.activityInfo.name.equals(ai.name)) { continue; } if (removeMatches) { pir.removeFilter(pa); changed = true; if (DEBUG_PREFERRED) { Slog.v(TAG, "Removing match " + pa.mPref.mComponent); } break; } // Okay we found a previously set preferred or last chosen app. // If the result set is different from when this // was created, we need to clear it and re-ask the // user their preference, if we're looking for an "always" type entry. if (always && !pa.mPref.sameSet(query)) { Slog.i(TAG, "Result set changed, dropping preferred activity for " + intent + " type " + resolvedType); if (DEBUG_PREFERRED) { Slog.v(TAG, "Removing preferred activity since set changed " + pa.mPref.mComponent); } pir.removeFilter(pa); // Re-add the filter as a "last chosen" entry (!always) PreferredActivity lastChosen = new PreferredActivity( pa, pa.mPref.mMatch, null, pa.mPref.mComponent, false); pir.addFilter(lastChosen); changed = true; return null; } // Yay! Either the set matched or we're looking for the last chosen if (DEBUG_PREFERRED || debug) Slog.v(TAG, "Returning preferred activity: " + ri.activityInfo.packageName + "/" + ri.activityInfo.name); return ri; } } } finally { if (changed) { if (DEBUG_PREFERRED) { Slog.v(TAG, "Preferred activity bookkeeping changed; writing restrictions"); } scheduleWritePackageRestrictionsLocked(userId); } } } } if (DEBUG_PREFERRED || debug) Slog.v(TAG, "No preferred activity to return"); return null; }原因与解决方案分解下出问题时的步骤:安装新的Launcher点击HOME键, 并从列表中选择一个默认为默认重启主板主板显示列表选择框.出现问题的地方在第4步从上面的LOG可以看出, 设置默认时的信息是: act=android.intent.action.MAIN cat=[android.intent.category.HOME,android.intent.category.DEFAULT]在重启后, 过入了FallbackHome, 在FallbackHome有以下代码调用PM的resolveActivity方法, 而此方法传入的Intent为act=android.intent.action.MAIN cat=[android.intent.category.HOME]: private void maybeFinish() { if (getSystemService(UserManager.class).isUserUnlocked()) { final Intent homeIntent = new Intent(Intent.ACTION_MAIN) .addCategory(Intent.CATEGORY_HOME); final ResolveInfo homeInfo = getPackageManager().resolveActivity(homeIntent, 0); if (Objects.equals(getPackageName(), homeInfo.activityInfo.packageName)) { Log.d(TAG, "User unlocked but no home; let's hope someone enables one soon?"); mHandler.sendEmptyMessageDelayed(0, 200); } else { Log.d(TAG, "User unlocked and real home found; let's go!"); getSystemService(PowerManager.class).userActivity( SystemClock.uptimeMillis(), false); finish(); } } }在FallbackHome执行完后, PM会删除默认信息: PackageManager: Removing preferred activity since set changed ComponentInfo{com.teslacoilsw.launcher/com.teslacoilsw.launcher.NovaLauncher}删除默认信息后, 当FallbackHome finish自己后, 系统重新startHome时, 就会出现, 未找到默认, 并显示列表选择框启动后, 第一个进入的Launcher是 Settings中的 FallbackHome, 在启动初始化完成后, FallbackHome会Finsish自己, 并交由系统去启动新的Launcher.问题出现时, 在PM中查找Launcher的数量与之前设置默认时不一致:第一次是4个:{ActivityInfo{da70dd6 com.android.launcher3.Launcher}} {ActivityInfo{fdc4857 com.teslacoilsw.launcher.NovaLauncher}} {ActivityInfo{91f7f44 teaonly.rk.droidipcam.CameraActivity}} {ActivityInfo{6138c45 com.android.settings.FallbackHome}}在后面选择了默认后, 是3个:{ActivityInfo{da70dd6 com.android.launcher3.Launcher}} {ActivityInfo{fdc4857 com.teslacoilsw.launcher.NovaLauncher}} {ActivityInfo{6138c45 com.android.settings.FallbackHome}}多出来的一个 CameraActivity定义如下(缺少了category.DEFAULT):<activity android:name="teaonly.rk.droidipcam.CameraActivity" android:label="@string/app_name" android:screenOrientation="landscape" > <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.HOME" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity>之所有会出现数量上的差别, 是由于在调用PM的resolveIntent遍历时, 有两个相关的因素:传去的FLAG不同: PackageManager.MATCH_DEFAULT_ONLY(0x00010000)Intent中带的信息不同.解决方案:11.1 修改 FallbackHome 的 maybeFinish函数private void maybeFinish() { if (getSystemService(UserManager.class).isUserUnlocked()) { final Intent homeIntent = new Intent(Intent.ACTION_MAIN) .addCategory(Intent.CATEGORY_HOME). //添加DEFAULT使Intent保持与保存默认的信息一致 .addCategory(Intent.CATEGORY_DEFAULT); //... } }1.2 同样修改 FallbackHome 的 maybeFinish函数private void maybeFinish() { //... //0 -> android.content.pm.PackageManager.MATCH_DEFAULT_ONLY final ResolveInfo homeInfo = getPackageManager().resolveActivity(homeIntent, android.content.pm.PackageManager.MATCH_DEFAULT_ONLY); //... }PS 1/2 的方法需配合修改:|–frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.javaIntent getHomeIntent() { Intent intent = new Intent(mTopAction, mTopData != null ? Uri.parse(mTopData) : null); intent.setComponent(mTopComponent); intent.addFlags(Intent.FLAG_DEBUG_TRIAGED_MISSING); if (mFactoryTest != FactoryTest.FACTORY_TEST_LOW_LEVEL) { intent.addCategory(Intent.CATEGORY_HOME); //添加DEFAULT intent.addCategory(Intent.CATEGORY_DEFAULT); } return intent; }2在PM中强制为Launcher的过滤添加 DEFAULT--- a/frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java @@ -4830,6 +4830,14 @@ public class PackageManagerService extends IPackageManager.Stub { } } + //AnsonCode + boolean isHome(Intent intent){ + if(intent != null && intent.getCategories() != null){ + return intent.getAction().equals(Intent.ACTION_MAIN) && intent.getCategories().contains(Intent.CATEGORY_HOME); + } + return false; + } + @Override public ResolveInfo resolveIntent(Intent intent, String resolvedType, int flags, int userId) { @@ -4842,6 +4850,10 @@ public class PackageManagerService extends IPackageManager.Stub { false /*requireFullPermission*/, false /*checkShell*/, "resolve intent"); Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "queryIntentActivities"); + //AnsonCode + if(isHome(intent)){ + flags |= PackageManager.MATCH_DEFAULT_ONLY; + } final List<ResolveInfo> query = queryIntentActivitiesInternal(intent, resolvedType, flags, userId); Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);扩展FallbackHome 与 LauncherFallbackHome的注册信息:<activity android:name=".FallbackHome" android:excludeFromRecents="true" android:screenOrientation="nosensor" android:theme="@style/FallbackHome"> <intent-filter android:priority="-1000"> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.HOME" /> <category android:name="android.intent.category.DEFAULT" /> </intent-filter> </activity>Launcher的注册信息:<activity android:name="com.android.launcher3.Launcher" android:launchMode="singleTask" android:clearTaskOnLaunch="true" android:stateNotNeeded="true" android:theme="@style/LauncherTheme" android:windowSoftInputMode="adjustPan" android:configChanges="keyboard|keyboardHidden|navigation" android:resumeWhilePausing="true" android:taskAffinity="" android:enabled="true"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.HOME" /> <category android:name="android.intent.category.DEFAULT" /> <category android:name="android.intent.category.MONKEY"/> </intent-filter> </activity>启动的顺序:2019-11-22 14:55:32.453 system_process I/ActivityManager: START u0 {act=android.intent.action.MAIN cat=[android.intent.category.HOME] flg=0x10000100 cmp=com.android.settings/.FallbackHome} from uid 0 on display 0 2019-11-22 14:55:35.073 system_process I/ActivityManager: START u0 {act=android.intent.action.MAIN cat=[android.intent.category.HOME] flg=0x10000100 cmp=com.android.launcher3/.Launcher} from uid 0 on display 0首先, FallbackHome的优先级是比较低的, 但反而是先于launcher启动, 主要是由于Settings中有 android:directBootAware="true"的定义,参见android 7.1 缺少设置directBootAware导致无法启动指定Launcher偏好activity储存位置: ./system/users/0/package-restrictions.xml
平台Ubuntu 16.04 x64Android Studio 3.5.2gradle-5.4.1com.android.tools.build:gradle 3.5.1问题描述之前开发的一些测试用的代码中, 有此包含了JNI的so库, 存放目录为 src/main/jniLibs, 在更新之前, 不管是调试还是发布版应用, 都可以把so库正常打包到apk文件中,但在更新了版本后(studio 和 gradle都更新)发现, 调试过程中, 应用找不到so库, 后面发现, 打包出来的APK中缺少了lib目录.解决方案gradle 版本回退1.gradle/wrapper/gradle-wrapper.properties#Mon Nov 18 16:32:18 CST 2019 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists distributionUrl=https\://services.gradle.org/distributions/gradle-5.4.1-all.zipgradle-5.4.1 -> gradle-4.12.build.gradle dependencies { classpath 'com.android.tools.build:gradle:3.5.1' // NOTE: Do not place your application dependencies here; they belong // in the individual module build.gradle files }com.android.tools.build:gradle:3.5.1 -> com.android.tools.build:gradle:3.0.0扩展google gradle 插件与 gradle 版本对应
平台RK3288 + Android 7.1问题通过遥控操作打开设置后, 无法使用 上, 下, 左, 右, 确认键进行操作.分析类似的问题, 在之前有碰到过, 原因是焦点停留在了一些不可控的控件上.查下当前界面的焦点:dumpsys activity com.android.settings/.SettingsTASK com.android.settings id=11 ACTIVITY com.android.settings/.Settings d201ac0 pid=643 Local Activity 1e194fb State: mResumed=true mStopped=false mFinished=false mChangingConfigurations=false mCurrentConfig={1.0 dualscreenflag=DISABLE ?mcc?mnc [zh_CN] ldltr sw1080dp w1920dp h1000dp 160dpi xlrg long land -touch -keyb/v/h -nav/h s.4} mLoadersStarted=true Loader Manager 4fbf7ac: Active Loaders: #1: LoaderInfo{fc70c75 #1 : PrintServicesLoader{50a240a}} mId=1 mArgs=null mCallbacks=com.android.settings.search.DynamicIndexableContentMonitor@d2caec4 mLoader=PrintServicesLoader{50a240a id=1} mId=1 mListener=LoaderInfo{fc70c75 #1 : PrintServicesLoader{50a240a}} mStarted=true mContentChanged=false mProcessingChange=false mHaveData=true mDeliveredData=true mData=[] mStarted=true mReportNextStart=false mDestroyed=false mRetaining=false mRetainingStarted=false mListenerRegistered=true Active Fragments in 608947b: #0: DashboardContainerFragment{106e298 #0 id=0x7f110224} mFragmentId=#7f110224 mContainerId=#7f110224 mTag=null mState=5 mIndex=0 mWho=android:fragment:0 mBackStackNesting=0 mAdded=true mRemoving=false mFromLayout=false mInLayout=false mHidden=false mDetached=false mMenuVisible=true mHasMenu=true mRetainInstance=false mRetaining=false mUserVisibleHint=true mFragmentManager=FragmentManager{608947b in HostCallbacks{288faf1}} mHost=android.app.Activity$HostCallbacks@288faf1 mArguments=Bundle[{:settings:select_settings_tab=null}] mContainer=android.widget.FrameLayout{82e76d6 V.E...... ........ 0,0-1920,936 #7f110224 app:id/main_content} mView=com.android.settings.widget.RtlCompatibleViewPager{381fd57 VFED..... ........ 0,0-1920,936 #7f11007e app:id/pager} Child FragmentManager{1d39044 in DashboardContainerFragment{106e298}}: Active Fragments in 1d39044: #0: DashboardSummary{5a1552d #0 id=0x7f11007e android:switcher:2131820670:0} mFragmentId=#7f11007e mContainerId=#7f11007e mTag=android:switcher:2131820670:0 mState=5 mIndex=0 mWho=android:fragment:0:0 mBackStackNesting=0 mAdded=true mRemoving=false mFromLayout=false mInLayout=false mHidden=false mDetached=false mMenuVisible=true mHasMenu=false mRetainInstance=false mRetaining=false mUserVisibleHint=true mFragmentManager=FragmentManager{1d39044 in DashboardContainerFragment{106e298}} mHost=android.app.Activity$HostCallbacks@288faf1 mParentFragment=DashboardContainerFragment{106e298 #0 id=0x7f110224} mContainer=com.android.settings.widget.RtlCompatibleViewPager{381fd57 VFED..... ........ 0,0-1920,936 #7f11007e app:id/pager} mView=com.android.settings.dashboard.conditional.FocusRecyclerView{b732a62 VFED.V... .F...... 0,0-1920,936 #7f1100e3 app:id/dashboard_container} Child FragmentManager{bf17f3 in DashboardSummary{5a1552d}}: FragmentManager misc state: mHost=android.app.Activity$HostCallbacks@288faf1 mContainer=android.app.Fragment$1@39b6cb0 mParent=DashboardSummary{5a1552d #0 id=0x7f11007e android:switcher:2131820670:0} mCurState=5 mStateSaved=false mDestroyed=false Added Fragments: #0: DashboardSummary{5a1552d #0 id=0x7f11007e android:switcher:2131820670:0} FragmentManager misc state: mHost=android.app.Activity$HostCallbacks@288faf1 mContainer=android.app.Fragment$1@46b1729 mParent=DashboardContainerFragment{106e298 #0 id=0x7f110224} mCurState=5 mStateSaved=false mDestroyed=false Added Fragments: #0: DashboardContainerFragment{106e298 #0 id=0x7f110224} Fragments Created Menus: #0: DashboardContainerFragment{106e298 #0 id=0x7f110224} FragmentManager misc state: mHost=android.app.Activity$HostCallbacks@288faf1 mContainer=android.app.Activity$HostCallbacks@288faf1 mCurState=5 mStateSaved=false mDestroyed=false ViewRoot: mAdded=true mRemoved=false mConsumeBatchedInputScheduled=false mConsumeBatchedInputImmediatelyScheduled=false mPendingInputEventCount=0 mProcessInputEventsScheduled=false mTraversalScheduled=false mIsAmbientMode=false android.view.ViewRootImpl$NativePreImeInputStage: mQueueLength=0 android.view.ViewRootImpl$ImeInputStage: mQueueLength=0 android.view.ViewRootImpl$NativePostImeInputStage: mQueueLength=0 Choreographer: mFrameScheduled=false mLastFrameTime=2865695 (727294 ms ago) View Hierarchy: DecorView@55d8aae[Settings] android.widget.LinearLayout{9a9404f V.E...... ........ 0,0-1920,1024} android.view.ViewStub{ac2a3dc G.E...... ......I. 0,0-0,0 #1020400 android:id/action_mode_bar_stub} android.widget.FrameLayout{af4fce5 V.E...... ........ 0,0-1920,1024 #1020002 android:id/content} android.support.v4.widget.DrawerLayout{d7ba3ba VFE...... ........ 0,0-1920,1024 #7f110227 app:id/drawer_layout} android.widget.LinearLayout{563926b V.E...... ........ 0,0-1920,1024 #7f110228 app:id/content_parent} android.widget.FrameLayout{bc421c8 V.E...... ........ 0,24-1920,88} android.widget.Toolbar{d7d8261 V.E...... ........ 0,0-1920,64 #7f110054 app:id/action_bar} android.widget.TextView{4304186 V.ED..... ........ 16,18-56,46} android.widget.ActionMenuView{26ea47 V.E...... ........ 1864,0-1912,64} com.android.internal.view.menu.ActionMenuItemView{5dd9274 VFED..CL. ........ 0,8-48,56 #7f110332 app:id/search} android.widget.FrameLayout{baee39d V.E...... ........ 0,88-1920,88 #7f110229 app:id/content_header_container} android.widget.FrameLayout{b3ef012 V.E...... ........ 0,88-1920,1024 #7f11022a app:id/content_frame} android.widget.FrameLayout{82e76d6 V.E...... ........ 0,0-1920,936 #7f110224 app:id/main_content} com.android.settings.widget.RtlCompatibleViewPager{381fd57 VFED..... ........ 0,0-1920,936 #7f11007e app:id/pager} com.android.settings.dashboard.conditional.FocusRecyclerView{b732a62 VFED.V... .F...... 0,0-1920,936 #7f1100e3 app:id/dashboard_container} android.widget.LinearLayout{5dea152 VFE...C.. ........ 160,0-1760,48} android.widget.ImageView{6dde3e3 V.ED..... ........ 16,14-40,38 #1020006 android:id/icon} android.widget.TextView{c7b61e0 V.ED..... ........ 72,16-100,35 #1020016 android:id/title} android.widget.TextView{b9b1c99 V.ED..... ........ 100,16-1600,35 #1020010 android:id/summary} android.widget.LinearLayout{959cca1 VFE...C.. ........ 160,48-1760,120} android.widget.ImageView{b17fb5e V.ED..... ........ 16,24-40,48 #1020006 android:id/icon} android.widget.RelativeLayout{80db3f V.E...... ........ 72,15-1560,56} android.widget.TextView{b64bc0c V.ED..... ........ 0,0-96,22 #1020016 android:id/title} android.widget.TextView{877e955 V.ED..... ........ 0,22-84,41 #1020010 android:id/summary} android.widget.ImageView{e46f6a V.ED..C.. ........ 1560,8-1600,64 #7f110247 app:id/overflow} android.widget.LinearLayout{6511b4 VFE...C.. ........ 160,120-1760,192} android.widget.ImageView{131ec5b V.ED..... ........ 16,24-40,48 #1020006 android:id/icon} android.widget.RelativeLayout{1a78cf8 V.E...... ........ 72,15-1560,56} android.widget.TextView{11ac5d1 V.ED..... ........ 0,0-64,22 #1020016 android:id/title} android.widget.TextView{1521836 V.ED..... ........ 0,22-140,41 #1020010 android:id/summary} android.widget.ImageView{318f337 V.ED..C.. ........ 1560,8-1600,64 #7f110247 app:id/overflow} android.widget.LinearLayout{936cfa V.E...... ........ 160,192-1760,240 #7f1100e4 app:id/category} android.widget.TextView{f4480a4 V.ED..... ........ 0,0-1600,40 #1020016 android:id/title} android.widget.LinearLayout{eabde87 VFE...C.. ........ 160,240-1760,312 #7f1100e6 app:id/dashboard_tile} android.widget.ImageView{234ee0d V.ED..... ........ 16,24-40,48 #1020006 android:id/icon} android.widget.LinearLayout{c1f81c2 V.E...... ........ 72,25-1600,47} android.widget.TextView{ff8bd3 V.ED..... ........ 0,0-44,22 #1020016 android:id/title} android.widget.TextView{19b0310 G.ED..... ......I. 0,0-0,0 #1020010 android:id/summary} android.widget.LinearLayout{96cec8f VFE...C.. ........ 160,312-1760,384 #7f1100e6 app:id/dashboard_tile} android.widget.ImageView{84f5e09 V.ED..... ........ 16,24-40,48 #1020006 android:id/icon} android.widget.LinearLayout{c67f80e V.E...... ........ 72,15-1600,56} android.widget.TextView{ead122f V.ED..... ........ 0,0-32,22 #1020016 android:id/title} android.widget.TextView{a95403c V.ED..... ........ 0,22-58,41 #1020010 android:id/summary} android.widget.LinearLayout{31b9520 VFE...C.. ........ 160,384-1760,456 #7f1100e6 app:id/dashboard_tile} android.widget.ImageView{586d1c5 V.ED..... ........ 16,24-40,48 #1020006 android:id/icon} android.widget.LinearLayout{1af871a V.E...... ........ 72,15-1600,56} android.widget.TextView{b02a24b V.ED..... ........ 0,0-96,22 #1020016 android:id/title} android.widget.TextView{e942428 V.ED..... ........ 0,22-126,41 #1020010 android:id/summary} android.widget.LinearLayout{8552325 VFE...C.. ........ 160,456-1760,528 #7f1100e6 app:id/dashboard_tile} android.widget.ImageView{707c541 V.ED..... ........ 16,24-40,48 #1020006 android:id/icon} android.widget.LinearLayout{daefae6 V.E...... ........ 72,25-1600,47} android.widget.TextView{7d71827 V.ED..... ........ 0,0-32,22 #1020016 android:id/title} android.widget.TextView{51b5ad4 G.ED..... ......I. 0,0-0,0 #1020010 android:id/summary} android.widget.LinearLayout{c5ddc23 V.E...... ........ 160,528-1760,576 #7f1100e4 app:id/category} android.widget.TextView{64a747d V.ED..... ........ 0,0-1600,40 #1020016 android:id/title} android.widget.LinearLayout{d55c2ab VFE...C.. ........ 160,576-1760,648 #7f1100e6 app:id/dashboard_tile} android.widget.ImageView{2dfdf72 V.ED..... ........ 16,24-40,48 #1020006 android:id/icon} android.widget.LinearLayout{3930fc3 V.E...... ........ 72,15-1600,56} android.widget.TextView{83d5040 V.ED..... ........ 0,0-32,22 #1020016 android:id/title} android.widget.TextView{20edb79 V.ED..... ........ 0,22-170,41 #1020010 android:id/summary} android.widget.LinearLayout{a162d08 VFE...C.. ........ 160,648-1760,720 #7f1100e6 app:id/dashboard_tile} android.widget.ImageView{fc880be V.ED..... ........ 16,24-40,48 #1020006 android:id/icon} android.widget.LinearLayout{8ce51f V.E...... ........ 72,15-1600,56} android.widget.TextView{ec7306c V.ED..... ........ 0,0-32,22 #1020016 android:id/title} android.widget.TextView{b18b635 V.ED..... ........ 0,22-170,41 #1020010 android:id/summary} android.widget.LinearLayout{d1b5ec6 VFE...C.. ........ 160,720-1760,792 #7f1100e6 app:id/dashboard_tile} android.widget.ImageView{307eaca V.ED..... ........ 16,24-40,48 #1020006 android:id/icon} android.widget.LinearLayout{624b43b V.E...... ........ 72,15-1600,56} android.widget.TextView{d2ce758 V.ED..... ........ 0,0-32,22 #1020016 android:id/title} android.widget.TextView{ab80b1 V.ED..... ........ 0,22-115,41 #1020010 android:id/summary} android.widget.LinearLayout{90e7b1c VFE...C.. ........ 160,792-1760,864 #7f1100e6 app:id/dashboard_tile} android.widget.ImageView{421e996 V.ED..... ........ 16,24-40,48 #1020006 android:id/icon} android.widget.LinearLayout{7a05917 V.E...... ........ 72,15-1600,56} android.widget.TextView{9352104 V.ED..... ........ 0,0-32,22 #1020016 android:id/title} android.widget.TextView{8c676ed V.ED..... ........ 0,22-122,41 #1020010 android:id/summary} android.widget.LinearLayout{ba591dd VFE...C.. ........ 160,864-1760,936 #7f1100e6 app:id/dashboard_tile} android.widget.ImageView{d0b0922 V.ED..... ........ 16,24-40,48 #1020006 android:id/icon} android.widget.LinearLayout{cc76fb3 V.E...... ........ 72,25-1600,47} android.widget.TextView{c654970 V.ED..... ........ 0,0-64,22 #1020016 android:id/title} android.widget.TextView{2094e9 G.ED..... ......I. 0,0-0,0 #1020010 android:id/summary} android.widget.ListView{74956e IFED.VC.. ......ID -300,0-0,1024 #7f11022b app:id/left_drawer} android.widget.Space{83f540f I.ED..... ......I. 0,0-300,32 #7f11003e app:id/spacer} android.widget.LinearLayout{12d8c9c V.E...... ......ID 0,31-300,79 #7f11011f app:id/tile_item} android.widget.ImageView{de496a5 V.ED..... ......ID 0,12-72,36 #1020006 android:id/icon} android.widget.TextView{8d89a7a V.ED..... ......ID 72,11-162,36 #1020016 android:id/title} android.widget.LinearLayout{7a7222b V.E...... ......ID 0,78-300,138} android.view.View{6d4d688 V.ED..... ......ID 0,8-300,9} android.widget.TextView{72cf821 V.ED..... ......ID 0,9-300,60 #1020016 android:id/title} android.widget.LinearLayout{c45e446 V.E...... ......ID 0,137-300,185 #7f11011f app:id/tile_item} android.widget.ImageView{973b607 V.ED..... ......ID 0,12-72,36 #1020006 android:id/icon} android.widget.TextView{824d334 V.ED..... ......ID 72,11-123,36 #1020016 android:id/title} android.widget.LinearLayout{e3ff55d V.E...... ......ID 0,184-300,232 #7f11011f app:id/tile_item} android.widget.ImageView{ebfed2 V.ED..... ......ID 0,12-72,36 #1020006 android:id/icon} android.widget.TextView{48baba3 V.ED..... ......ID 72,11-108,36 #1020016 android:id/title} android.widget.LinearLayout{d5eea0 V.E...... ......ID 0,231-300,279 #7f11011f app:id/tile_item} android.widget.ImageView{98b8a59 V.ED..... ......ID 0,12-72,36 #1020006 android:id/icon} android.widget.TextView{e67361e V.ED..... ......ID 72,11-180,36 #1020016 android:id/title} android.widget.LinearLayout{da35eff V.E...... ......ID 0,278-300,326 #7f11011f app:id/tile_item} android.widget.ImageView{dbb54cc V.ED..... ......ID 0,12-72,36 #1020006 android:id/icon} android.widget.TextView{e617315 V.ED..... ......ID 72,11-108,36 #1020016 android:id/title} android.widget.LinearLayout{7cc962a V.E...... ......ID 0,325-300,385} android.view.View{658ec1b V.ED..... ......ID 0,8-300,9} android.widget.TextView{3aef1b8 V.ED..... ......ID 0,9-300,60 #1020016 android:id/title} android.widget.LinearLayout{b732b91 V.E...... ......ID 0,384-300,432 #7f11011f app:id/tile_item} android.widget.ImageView{a75eaf6 V.ED..... ......ID 0,12-72,36 #1020006 android:id/icon} android.widget.TextView{2102ef7 V.ED..... ......ID 72,11-108,36 #1020016 android:id/title} android.widget.LinearLayout{93d7164 V.E...... ......ID 0,431-300,479 #7f11011f app:id/tile_item} android.widget.ImageView{f0defcd V.ED..... ......ID 0,12-72,36 #1020006 android:id/icon} android.widget.TextView{d8dc082 V.ED..... ......ID 72,11-108,36 #1020016 android:id/title} android.widget.LinearLayout{c8ec393 V.E...... ......ID 0,478-300,526 #7f11011f app:id/tile_item} android.widget.ImageView{f123fd0 V.ED..... ......ID 0,12-72,36 #1020006 android:id/icon} android.widget.TextView{516bbc9 V.ED..... ......ID 72,11-108,36 #1020016 android:id/title} android.widget.LinearLayout{e5b62ce V.E...... ......ID 0,525-300,573 #7f11011f app:id/tile_item} android.widget.ImageView{e5805ef V.ED..... ......ID 0,12-72,36 #1020006 android:id/icon} android.widget.TextView{32388fc V.ED..... ......ID 72,11-108,36 #1020016 android:id/title} android.widget.LinearLayout{8c64b85 V.E...... ......ID 0,572-300,620 #7f11011f app:id/tile_item} android.widget.ImageView{54eddda V.ED..... ......ID 0,12-72,36 #1020006 android:id/icon} android.widget.TextView{ac9120b V.ED..... ......ID 72,11-144,36 #1020016 android:id/title} android.widget.LinearLayout{a9e38e8 V.E...... ......ID 0,619-300,667 #7f11011f app:id/tile_item} android.widget.ImageView{6251b01 V.ED..... ......ID 0,12-72,36 #1020006 android:id/icon} android.widget.TextView{fccfda6 V.ED..... ......ID 72,11-106,36 #1020016 android:id/title} android.widget.LinearLayout{3f4c3e7 V.E...... ......ID 0,666-300,714 #7f11011f app:id/tile_item} android.widget.ImageView{e91fb94 V.ED..... ......ID 0,12-72,36 #1020006 android:id/icon} android.widget.TextView{747663d V.ED..... ......ID 72,11-108,36 #1020016 android:id/title} android.widget.LinearLayout{abb4e32 V.E...... ......ID 0,713-300,761 #7f11011f app:id/tile_item} android.widget.ImageView{3fb783 V.ED..... ......ID 0,12-72,36 #1020006 android:id/icon} android.widget.TextView{75d3d00 V.ED..... ......ID 72,11-108,36 #1020016 android:id/title} android.widget.LinearLayout{9492939 V.E...... ......ID 0,760-300,808 #7f11011f app:id/tile_item} android.widget.ImageView{9cc1b7e V.ED..... ......ID 0,12-72,36 #1020006 android:id/icon} android.widget.TextView{dbc48df V.ED..... ......ID 72,11-108,36 #1020016 android:id/title} android.widget.LinearLayout{2d9292c V.E...... ......ID 0,807-300,855 #7f11011f app:id/tile_item} android.widget.ImageView{50a1ff5 V.ED..... ......ID 0,12-72,36 #1020006 android:id/icon} android.widget.TextView{78a718a V.ED..... ......ID 72,11-108,36 #1020016 android:id/title} android.widget.LinearLayout{f4693fb V.E...... ......ID 0,854-300,914} android.view.View{145ac18 V.ED..... ......ID 0,8-300,9} android.widget.TextView{7a9c671 V.ED..... ......ID 0,9-300,60 #1020016 android:id/title} android.widget.LinearLayout{a261c56 V.E...... ......ID 0,913-300,961 #7f11011f app:id/tile_item} android.widget.ImageView{f6074d7 V.ED..... ......ID 0,12-72,36 #1020006 android:id/icon} android.widget.TextView{4f571c4 V.ED..... ......ID 72,11-144,36 #1020016 android:id/title} android.widget.LinearLayout{6c358ad V.E...... ......ID 0,960-300,1008 #7f11011f app:id/tile_item} android.widget.ImageView{8ffa7e2 V.ED..... ......ID 0,12-72,36 #1020006 android:id/icon} android.widget.TextView{4cd8773 V.ED..... ......ID 72,11-108,36 #1020016 android:id/title} android.widget.LinearLayout{b9e630 V.E...... ......ID 0,1007-300,1055 #7f11011f app:id/tile_item} android.widget.ImageView{c69d2a9 V.ED..... ......ID 0,12-72,36 #1020006 android:id/icon} android.widget.TextView{ef4602e V.ED..... ......ID 72,11-108,36 #1020016 android:id/title} android.view.View{4ef27cf V.ED..... ........ 0,1024-1920,1080 #1020030 android:id/navigationBarBackground} android.view.View{10f355c V.ED..... ........ 0,0-1920,24 #102002f android:id/statusBarBackground} Looper (main, tid 1) {db1cb03} (Total messages: 0, polling=false, quitting=false)重点看下 View Hierarchy:当前的焦点停留在: com.android.settings.dashboard.conditional.FocusRecyclerView{b732a62 VFED.V… .F… 0,0-1920,936 #7f1100e3 app:id/dashboard_container}而我们预期的是停留在 FocusRecyclerView 的子控件中, 于是, 简单的处理下按键处理:|–packages/apps/Settings/src/com/android/settings/SettingsActivity.javadiff --git a/packages/apps/Settings/src/com/android/settings/SettingsActivity.java b/packages/apps/Settings/src/com/android/settings/SettingsActivity.java index e04c90a..60f6ca0 100755 --- a/packages/apps/Settings/src/com/android/settings/SettingsActivity.java +++ b/packages/apps/Settings/src/com/android/settings/SettingsActivity.java @@ -714,6 +714,22 @@ public class SettingsActivity extends SettingsDrawerActivity + " ms"); } + @Override + public boolean onKeyDown(int keyCode, android.view.KeyEvent event) { + View focus = getCurrentFocus(); + if(focus != null && keyCode == android.view.KeyEvent.KEYCODE_DPAD_DOWN){ + int listRootId = R.id.dashboard_container; + if(listRootId == focus.getId()){ + //Focus list parent. + com.android.settings.dashboard.conditional.FocusRecyclerView frv = (com.android.settings.dashboard.conditional.FocusRecyclerView)findViewById(listRootId); + View first = frv.getChildAt(0); + first.requestFocus(); + } + } + return super.onKeyDown(keyCode, event); + } + public void setDisplaySearchMenu(boolean displaySearch) { if (displaySearch != mDisplaySearch) { mDisplaySearch = displaySearch;
平台RK3288 + Android 7.1概述从Launcher中启动应用和从Recent列表中启动应用是否是一致的?有以下几种情况:应用未启动过 |-launcher启动:2017-01-01 21:12:56.490 system_process I/ActivityManager: START u0 {act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10200000 cmp=com.android.calculator2/.Calculator bnds=[960,678][1235,834] (has extras)} from uid 10036 on display 0 2017-01-01 21:12:56.512 system_process I/ActivityManager: Start proc 1719:com.android.calculator2/u0a32 for activity com.android.calculator2/.Calculator 2017-01-01 21:12:57.070 system_process I/ActivityManager: Displayed com.android.calculator2/.Calculator: +569ms |-Recent启动: 2017-01-01 21:15:11.067 system_process I/ActivityManager: START u0 {act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10300000 cmp=com.android.calculator2/.Calculator} from uid 10036 on display 0 2017-01-01 21:15:11.108 system_process I/ActivityManager: Start proc 1394:com.android.calculator2/u0a32 for activity com.android.calculator2/.Calculator 2017-01-01 21:15:11.578 system_process I/ActivityManager: Displayed com.android.calculator2/.Calculator: +492ms应用已启动, 但使用HOME键切换到了后台 |-Launcher2017-01-01 21:21:25.143 system_process I/ActivityManager: START u0 {act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10200000 cmp=com.android.calculator2/.Calculator bnds=[960,678][1235,834] (has extras)} from uid 10036 on display 0 |-Recent 2017-01-01 21:22:17.313 system_process E/ActivityManager: applyOptionsLocked: Unknown animationType=0应用已启动, 但已通过BACK键退出. |-Launcher2017-01-01 21:17:57.950 system_process I/ActivityManager: START u0 {act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10200000 cmp=com.android.calculator2/.Calculator bnds=[960,678][1235,834] (has extras)} from uid 10036 on display 0 2017-01-01 21:17:58.284 system_process I/ActivityManager: Displayed com.android.calculator2/.Calculator: +325ms |-Recent 2017-01-01 21:18:57.879 system_process E/ActivityManager: applyOptionsLocked: Unknown animationType=0LOG并不详尽, 仅供参考;从上面中可以看出启动过程中除了第一种情况, 后面两种都存在差区别, 暂时没有深入研究的打算.分析先看layout布局, AndroidStudio > Tools > Layout Inspector如图:|-- frameworks/base/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java@Override public void onClick(final View v) { if (mIsDisabledInSafeMode) { Context context = getContext(); String msg = context.getString(R.string.recents_launch_disabled_message, mTask.title); if (mDisabledAppToast != null) { mDisabledAppToast.cancel(); } mDisabledAppToast = Toast.makeText(context, msg, Toast.LENGTH_SHORT); mDisabledAppToast.show(); return; } boolean screenPinningRequested = false; if (v == mActionButtonView) { // Reset the translation of the action button before we animate it out mActionButtonView.setTranslationZ(0f); screenPinningRequested = true; } EventBus.getDefault().send(new LaunchTaskEvent(this, mTask, null, INVALID_STACK_ID, screenPinningRequested)); MetricsLogger.action(v.getContext(), MetricsEvent.ACTION_OVERVIEW_SELECT, mTask.key.getComponent().toString()); }//LaunchTaskEvent, 保存任务信息. |-- frameworks/base/packages/SystemUI/src/com/android/systemui/recents/events/activity/LaunchTaskEvent.java public class LaunchTaskEvent extends EventBus.Event { public final TaskView taskView; public final Task task; public final Rect targetTaskBounds; public final int targetTaskStack; public final boolean screenPinningRequested; public LaunchTaskEvent(TaskView taskView, Task task, Rect targetTaskBounds, int targetTaskStack, boolean screenPinningRequested) { this.taskView = taskView; this.task = task; this.targetTaskBounds = targetTaskBounds; this.targetTaskStack = targetTaskStack; this.screenPinningRequested = screenPinningRequested; } }|-- frameworks/base/packages/SystemUI/src/com/android/systemui/recents/events/EventBus.javapublic class EventBus extends BroadcastReceiver { private static final String TAG = "EventBus"; private static final boolean DEBUG_TRACE_ALL = false; //... /** * An event super class that allows us to track internal event state across subscriber * invocations. * * Events should not be edited by subscribers. */ public static class Event implements Cloneable { // Indicates that this event's dispatch should be traced and logged to logcat boolean trace; // Indicates that this event must be posted on the EventBus's looper thread before invocation boolean requiresPost; // Not currently exposed, allows a subscriber to cancel further dispatch of this event boolean cancelled; // Only accessible from derived events protected Event() {} /** * Called by the EventBus prior to dispatching this event to any subscriber of this event. */ void onPreDispatch() { // Do nothing } /** * Called by the EventBus after dispatching this event to every subscriber of this event. */ void onPostDispatch() { // Do nothing } @Override protected Object clone() throws CloneNotSupportedException { Event evt = (Event) super.clone(); // When cloning an event, reset the cancelled-dispatch state evt.cancelled = false; return evt; } } //--------------真正干活的:--------------------- //... //--------------------单例, 没什么特别的------------- /** * @return the default event bus for the application's main thread. */ public static EventBus getDefault() { if (sDefaultBus == null) synchronized (sLock) { if (sDefaultBus == null) { if (DEBUG_TRACE_ALL) { logWithPid("New EventBus"); } sDefaultBus = new EventBus(Looper.getMainLooper()); } } return sDefaultBus; } /** * Sends an event to the subscribers of the given event type immediately. This can only be * called from the same thread as the EventBus's looper thread (for the default EventBus, this * is the main application thread). */ public void send(Event event) { // Fail immediately if we are being called from the non-main thread long callingThreadId = Thread.currentThread().getId(); if (callingThreadId != mHandler.getLooper().getThread().getId()) { throw new RuntimeException("Can not send() a message from a non-main thread."); } if (DEBUG_TRACE_ALL) { logWithPid("send(" + event.getClass().getSimpleName() + ")"); } // Reset the event's cancelled state event.requiresPost = false; event.cancelled = false; queueEvent(event); } /** * Adds a new message. */ private void queueEvent(final Event event) { ArrayList<EventHandler> eventHandlers = mEventTypeMap.get(event.getClass()); if (eventHandlers == null) { return; } // Prepare this event boolean hasPostedEvent = false; event.onPreDispatch(); // We need to clone the list in case a subscriber unregisters itself during traversal // TODO: Investigate whether we can skip the object creation here eventHandlers = (ArrayList<EventHandler>) eventHandlers.clone(); int eventHandlerCount = eventHandlers.size(); for (int i = 0; i < eventHandlerCount; i++) { final EventHandler eventHandler = eventHandlers.get(i); if (eventHandler.subscriber.getReference() != null) { if (event.requiresPost) { mHandler.post(new Runnable() { @Override public void run() { processEvent(eventHandler, event); } }); hasPostedEvent = true; } else { processEvent(eventHandler, event); } } } // Clean up after this event, deferring until all subscribers have been called if (hasPostedEvent) { mHandler.post(new Runnable() { @Override public void run() { event.onPostDispatch(); } }); } else { event.onPostDispatch(); } } /** * Processes and dispatches the given event to the given event handler, on the thread of whoever * calls this method. */ private void processEvent(final EventHandler eventHandler, final Event event) { // Skip if the event was already cancelled if (event.cancelled) { if (event.trace || DEBUG_TRACE_ALL) { logWithPid("Event dispatch cancelled"); } return; } try { if (event.trace || DEBUG_TRACE_ALL) { logWithPid(" -> " + eventHandler.toString()); } Object sub = eventHandler.subscriber.getReference(); if (sub != null) { long t1 = 0; if (DEBUG_TRACE_ALL) { t1 = SystemClock.currentTimeMicro(); } eventHandler.method.invoke(sub, event); if (DEBUG_TRACE_ALL) { long duration = (SystemClock.currentTimeMicro() - t1); mCallDurationMicros += duration; mCallCount++; logWithPid(eventHandler.method.toString() + " duration: " + duration + " microseconds, avg: " + (mCallDurationMicros / mCallCount)); } } else { Log.e(TAG, "Failed to deliver event to null subscriber"); } } catch (IllegalAccessException e) { Log.e(TAG, "Failed to invoke method", e.getCause()); } catch (InvocationTargetException e) { throw new RuntimeException(e.getCause()); } }eventHandler.method.invoke(sub, event);首先, 从mEventTypeMap拿出eventHandlers:ArrayList eventHandlers = mEventTypeMap.get(event.getClass());再调用eventHandlers所有的元素传入processEvent.mEventTypeMap|-- frameworks/base/packages/SystemUI/src/com/android/systemui/recents/events/EventBus.java/** * Registers a new subscriber. */ private void registerSubscriber(Object subscriber, int priority, MutableBoolean hasInterprocessEventsChangedOut) { // Fail immediately if we are being called from the non-main thread //... if (subscriberMethods != null) { if (DEBUG_TRACE_ALL) { logWithPid("Subscriber class type already registered"); } // If we've parsed this subscriber type before, just add to the set for all the known // events for (EventHandlerMethod method : subscriberMethods) { ArrayList<EventHandler> eventTypeHandlers = mEventTypeMap.get(method.eventType); eventTypeHandlers.add(new EventHandler(sub, method, priority)); sortEventHandlersByPriority(eventTypeHandlers); } mSubscribers.add(sub); return; } else { if (DEBUG_TRACE_ALL) { logWithPid("Subscriber class type requires registration"); } // If we are parsing this type from scratch, ensure we add it to the subscriber type // map, and pull out he handler methods below subscriberMethods = new ArrayList<>(); mSubscriberTypeMap.put(subscriberType, subscriberMethods); mSubscribers.add(sub); } //...接着后面有一系列反射赋值, 很重要.... //主要是找出对应的这个函数名. //private static final String METHOD_PREFIX = "onBusEvent"; }|-- frameworks/base/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java@Override protected void onAttachedToWindow() { EventBus.getDefault().register(this, RecentsActivity.EVENT_BUS_PRIORITY + 1); EventBus.getDefault().register(mTouchHandler, RecentsActivity.EVENT_BUS_PRIORITY + 2); super.onAttachedToWindow(); } public final void onBusEvent(LaunchTaskEvent event) { new Exception("ALog.onBusEvent").printStackTrace(); mLastTaskLaunchedWasFreeform = event.task.isFreeformTask(); mTransitionHelper.launchTaskFromRecents(getStack(), event.task, mTaskStackView, event.taskView, event.screenPinningRequested, event.targetTaskBounds, event.targetTaskStack); }|-- frameworks/base/packages/SystemUI/src/com/android/systemui/recents/views/RecentsTransitionHelper.java/** * Launches the specified {@link Task}. */ public void launchTaskFromRecents(final TaskStack stack, @Nullable final Task task, final TaskStackView stackView, final TaskView taskView, final boolean screenPinningRequested, final Rect bounds, final int destinationStack) { new Exception("ALog.launchTaskFromRecents").printStackTrace(); final ActivityOptions opts = ActivityOptions.makeBasic(); if (bounds != null) { opts.setLaunchBounds(bounds.isEmpty() ? null : bounds); } final ActivityOptions.OnAnimationStartedListener animStartedListener; final IAppTransitionAnimationSpecsFuture transitionFuture; if (taskView != null) { transitionFuture = getAppTransitionFuture(new AnimationSpecComposer() { @Override public List<AppTransitionAnimationSpec> composeSpecs() { return composeAnimationSpecs(task, stackView, destinationStack); } }); animStartedListener = new ActivityOptions.OnAnimationStartedListener() { @Override public void onAnimationStarted() { // If we are launching into another task, cancel the previous task's // window transition EventBus.getDefault().send(new CancelEnterRecentsWindowAnimationEvent(task)); EventBus.getDefault().send(new ExitRecentsWindowFirstAnimationFrameEvent()); stackView.cancelAllTaskViewAnimations(); if (screenPinningRequested) { // Request screen pinning after the animation runs mStartScreenPinningRunnable.taskId = task.key.id; mHandler.postDelayed(mStartScreenPinningRunnable, 350); } } }; } else { // This is only the case if the task is not on screen (scrolled offscreen for example) transitionFuture = null; animStartedListener = new ActivityOptions.OnAnimationStartedListener() { @Override public void onAnimationStarted() { // If we are launching into another task, cancel the previous task's // window transition EventBus.getDefault().send(new CancelEnterRecentsWindowAnimationEvent(task)); EventBus.getDefault().send(new ExitRecentsWindowFirstAnimationFrameEvent()); stackView.cancelAllTaskViewAnimations(); } }; } if (taskView == null) { // If there is no task view, then we do not need to worry about animating out occluding // task views, and we can launch immediately startTaskActivity(stack, task, taskView, opts, transitionFuture, animStartedListener); } else { LaunchTaskStartedEvent launchStartedEvent = new LaunchTaskStartedEvent(taskView, screenPinningRequested); if (task.group != null && !task.group.isFrontMostTask(task)) { launchStartedEvent.addPostAnimationCallback(new Runnable() { @Override public void run() { startTaskActivity(stack, task, taskView, opts, transitionFuture, animStartedListener); } }); EventBus.getDefault().send(launchStartedEvent); } else { EventBus.getDefault().send(launchStartedEvent); startTaskActivity(stack, task, taskView, opts, transitionFuture, animStartedListener); } } Recents.getSystemServices().sendCloseSystemWindows( BaseStatusBar.SYSTEM_DIALOG_REASON_HOME_KEY); } /** * Starts the activity for the launch task. * * @param taskView this is the {@link TaskView} that we are launching from. This can be null if * we are toggling recents and the launch-to task is now offscreen. */ private void startTaskActivity(TaskStack stack, Task task, @Nullable TaskView taskView, ActivityOptions opts, IAppTransitionAnimationSpecsFuture transitionFuture, final ActivityOptions.OnAnimationStartedListener animStartedListener) { SystemServicesProxy ssp = Recents.getSystemServices(); if (ssp.startActivityFromRecents(mContext, task.key, task.title, opts)) { // Keep track of the index of the task launch int taskIndexFromFront = 0; int taskIndex = stack.indexOfStackTask(task); if (taskIndex > -1) { taskIndexFromFront = stack.getTaskCount() - taskIndex - 1; } EventBus.getDefault().send(new LaunchTaskSucceededEvent(taskIndexFromFront)); } else { // Dismiss the task if we fail to launch it if (taskView != null) { taskView.dismissTask(); } // Keep track of failed launches EventBus.getDefault().send(new LaunchTaskFailedEvent()); } if (transitionFuture != null) { ssp.overridePendingAppTransitionMultiThumbFuture(transitionFuture, wrapStartedListener(animStartedListener), true /* scaleUp */); } }|-- frameworks/base/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java/** Starts an activity from recents. */ public boolean startActivityFromRecents(Context context, Task.TaskKey taskKey, String taskName, ActivityOptions options) { if (mIam != null) { try { if (taskKey.stackId == DOCKED_STACK_ID) { // We show non-visible docked tasks in Recents, but we always want to launch // them in the fullscreen stack. if (options == null) { options = ActivityOptions.makeBasic(); } options.setLaunchStackId(FULLSCREEN_WORKSPACE_STACK_ID); } mIam.startActivityFromRecents( taskKey.id, options == null ? null : options.toBundle()); return true; } catch (Exception e) { Log.e(TAG, context.getString(R.string.recents_launch_error_message, taskName), e); } } return false; }|-- frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java@Override public final int startActivityFromRecents(int taskId, Bundle bOptions) { if (checkCallingPermission(START_TASKS_FROM_RECENTS) != PackageManager.PERMISSION_GRANTED) { String msg = "Permission Denial: startActivityFromRecents called without " + START_TASKS_FROM_RECENTS; Slog.w(TAG, msg); throw new SecurityException(msg); } final long origId = Binder.clearCallingIdentity(); try { synchronized (this) { return mStackSupervisor.startActivityFromRecentsInner(taskId, bOptions); } } finally { Binder.restoreCallingIdentity(origId); } }剩下的就看ActivityManagerService的了…
平台RK3288 + Android 5.1SystemUI 启动:|-- frameworks/base/services/java/com/android/server/SystemServer.javaprivate void startOtherServices() { ... mActivityManagerService.systemReady(new Runnable() { @Override public void run() { Slog.i(TAG, "Making services ready"); .... try { startSystemUi(context); } catch (Throwable e) { reportWtf("starting System UI", e); } ... } } static final void startSystemUi(Context context) { Intent intent = new Intent(); intent.setComponent(new ComponentName("com.android.systemui", "com.android.systemui.SystemUIService")); //Slog.d(TAG, "Starting service: " + intent); context.startServiceAsUser(intent, UserHandle.OWNER); }启动的时间, 是在系统服务ready时候, 这时个WindowManagerService, ActivityManagerService, PackageManagerService等关键的服务已经就绪.|-- frameworks/base/packages/SystemUI/src/com/android/systemui/SystemUIService.javapublic class SystemUIService extends Service { @Override public void onCreate() { super.onCreate(); //关键代码: ((SystemUIApplication) getApplication()).startServicesIfNeeded(); } @Override public IBinder onBind(Intent intent) { return null; } @Override protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { SystemUI[] services = ((SystemUIApplication) getApplication()).getServices(); if (args == null || args.length == 0) { for (SystemUI ui: services) { pw.println("dumping service: " + ui.getClass().getName()); ui.dump(fd, pw, args); } } else { String svc = args[0]; for (SystemUI ui: services) { String name = ui.getClass().getName(); if (name.endsWith(svc)) { ui.dump(fd, pw, args); } } } } }|-- frameworks/base/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java/** * The classes of the stuff to start. */ private final Class<?>[] SERVICES = new Class[] { com.android.systemui.keyguard.KeyguardViewMediator.class, com.android.systemui.recent.Recents.class, com.android.systemui.volume.VolumeUI.class, com.android.systemui.statusbar.SystemBars.class, com.android.systemui.usb.StorageNotification.class, com.android.systemui.power.PowerUI.class, com.android.systemui.media.RingtonePlayer.class }; public void startServicesIfNeeded() { if (mServicesStarted) { return; } if (!mBootCompleted) { // check to see if maybe it was already completed long before we began // see ActivityManagerService.finishBooting() if ("1".equals(SystemProperties.get("sys.boot_completed"))) { mBootCompleted = true; if (DEBUG) Log.v(TAG, "BOOT_COMPLETED was already sent"); } } /**----启动 SERVICES 所有的组件:----**/ Log.v(TAG, "Starting SystemUI services."); final int N = SERVICES.length; for (int i=0; i<N; i++) { Class<?> cl = SERVICES[i]; if (DEBUG) Log.d(TAG, "loading: " + cl); try { mServices[i] = (SystemUI)cl.newInstance(); } catch (IllegalAccessException ex) { throw new RuntimeException(ex); } catch (InstantiationException ex) { throw new RuntimeException(ex); } mServices[i].mContext = this; mServices[i].mComponents = mComponents; if (DEBUG) Log.d(TAG, "running: " + mServices[i]); mServices[i].start(); if (mBootCompleted) { mServices[i].onBootCompleted(); } } mServicesStarted = true; }重点关注 com.android.systemui.statusbar.SystemBars.class, 聚焦后面我们研究状态栏.状态栏 + 导航栏的核心 PhoneStatusBar|-- frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/SystemBars.java@Override public void start() { if (DEBUG) Log.d(TAG, "start"); mServiceMonitor = new ServiceMonitor(TAG, DEBUG, mContext, Settings.Secure.BAR_SERVICE_COMPONENT, this); mServiceMonitor.start(); // will call onNoService if no remote service is found }因为在公版代码中, 并未设置 BAR_SERVICE_COMPONENT 所以, ServiceMonitor执行start后, 会回调@Override public void onNoService() { if (DEBUG) Log.d(TAG, "onNoService"); createStatusBarFromConfig(); // fallback to using an in-process implementation } private void createStatusBarFromConfig() { if (DEBUG) Log.d(TAG, "createStatusBarFromConfig"); String clsName = mContext.getString(R.string.config_statusBarComponent); /** frameworks/base/packages/SystemUI/res/values/config.xml: <string name="config_statusBarComponent" translatable="false">com.android.systemui.statusbar.phone.PhoneStatusBar</string> **/ if ("box".equals(SystemProperties.get("ro.target.product", "tablet"))&&!mContext.getResources().getConfiguration().enableMultiWindow()){ clsName = "com.android.systemui.statusbar.tv.TvStatusBar"; } if (clsName == null || clsName.length() == 0) { throw andLog("No status bar component configured", null); } Class<?> cls = null; try { cls = mContext.getClassLoader().loadClass(clsName); } catch (Throwable t) { throw andLog("Error loading status bar component: " + clsName, t); } try { mStatusBar = (BaseStatusBar) cls.newInstance(); } catch (Throwable t) { throw andLog("Error creating status bar component: " + clsName, t); } mStatusBar.mContext = mContext; mStatusBar.mComponents = mComponents; mStatusBar.start(); if (DEBUG) Log.d(TAG, "started " + mStatusBar.getClass().getSimpleName()); }到此, 终于进入主角: PhoneStatusBar|-- frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.javapublic void start() {//父类BaseStatusBar的函数 ... mBarService = IStatusBarService.Stub.asInterface( ServiceManager.getService(Context.STATUS_BAR_SERVICE)); mRecents = getComponent(RecentsComponent.class); mRecents.setCallback(this); final Configuration currentConfig = mContext.getResources().getConfiguration(); mLocale = currentConfig.locale; mLayoutDirection = TextUtils.getLayoutDirectionFromLocale(mLocale); mFontScale = currentConfig.fontScale; mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE); mLinearOutSlowIn = AnimationUtils.loadInterpolator(mContext, android.R.interpolator.linear_out_slow_in); mFastOutLinearIn = AnimationUtils.loadInterpolator(mContext, android.R.interpolator.fast_out_linear_in); // Connect in to the status bar manager service StatusBarIconList iconList = new StatusBarIconList(); mCommandQueue = new CommandQueue(this, iconList); ... /** ----添加状态栏----**/ createAndAddWindows(); ... }@Override public void start() { mDisplay = ((WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE)) .getDefaultDisplay(); updateDisplaySize(); mScrimSrcModeEnabled = mContext.getResources().getBoolean( R.bool.config_status_bar_scrim_behind_use_src); super.start(); // calls createAndAddWindows() ... // TODO: use MediaSessionManager.SessionListener to hook us up to future updates // in session state /** ----添加导航栏(BACK, HOME, RECENT)----**/ addNavigationBar(); ... } // For small-screen devices (read: phones) that lack hardware navigation buttons private void addNavigationBar() { if (DEBUG) Log.v(TAG, "addNavigationBar: about to add " + mNavigationBarView); if (mNavigationBarView == null) return; prepareNavigationBarView(); mWindowManager.addView(mNavigationBarView, getNavigationBarLayoutParams()); }@Override public void createAndAddWindows() { wm = (WindowManager) mContext.getSystemService( Context.WINDOW_SERVICE); mWallpaperManager = (WallpaperManager) mContext.getSystemService(Context.WALLPAPER_SERVICE); addMultiModeWindow(); addStatusBarWindow(); addHalfScreenWindowController(); if(IS_USE_WHCONTROLS){ addFourScreenWindowController(); } addCenterBtnWindow(); if(ONE_LEVEL_MENU){ addCircleMenuWindow(); } if(IS_USE_BACK_WINDOW){ if(mFourScreenBackWindow == null){ mFourScreenBackWindow = new FourScreenBackWindow(mContext, wm); } } if(mMinWindow == null){ mMinWindow = new MinWindow(mContext, wm); } } private void addStatusBarWindow() { makeStatusBarView(); mStatusBarWindowManager = new StatusBarWindowManager(mContext); mStatusBarWindowManager.add(mStatusBarWindow, getStatusBarHeight()); } // ================================================================================ // Constructing the view // ================================================================================ protected PhoneStatusBarView makeStatusBarView() { final Context context = mContext; IntentFilter intentfilter=new IntentFilter(); intentfilter.addAction("rk.android.screenshot.SHOW"); intentfilter.addAction("rk.android.screenshot.ACTION"); context.registerReceiver(receiver, intentfilter); IntentFilter winintentfilter=new IntentFilter(); winintentfilter.addAction("rk.android.wintask.SHOW"); winintentfilter.addAction("rk.android.wintask.FINISH"); context.registerReceiver(winreceiver, winintentfilter); IntentFilter packagefilter=new IntentFilter(); packagefilter.addAction(Intent.ACTION_PACKAGE_ADDED); packagefilter.addAction(Intent.ACTION_PACKAGE_REMOVED); packagefilter.addDataScheme("package"); context.registerReceiver(packagereceiver, packagefilter); mContext.registerReceiver(wallpaperReceiver, new IntentFilter(Intent.ACTION_WALLPAPER_CHANGED)); Resources res = context.getResources(); updateDisplaySize(); // populates mDisplayMetrics updateResources(); mIconSize = res.getDimensionPixelSize(com.android.internal.R.dimen.status_bar_icon_size); if(mContext.getResources().getConfiguration().enableMultiWindow()){ mStatusBarWindow = (StatusBarWindowView) View.inflate(context, R.layout.super_status_bar_win, null); }else{ mStatusBarWindow = (StatusBarWindowView) View.inflate(context, R.layout.super_status_bar, null); } mStatusBarWindow.mService = this; mStatusBarWindow.setOnTouchListener(new View.OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { checkUserAutohide(v, event); if (event.getAction() == MotionEvent.ACTION_DOWN) { if (mExpandedVisible) { animateCollapsePanels(); } } return mStatusBarWindow.onTouchEvent(event); }}); mStatusBarView = (PhoneStatusBarView) mStatusBarWindow.findViewById(R.id.status_bar); mStatusBarView.setBar(this); PanelHolder holder = (PanelHolder) mStatusBarWindow.findViewById(R.id.panel_holder); mStatusBarView.setPanelHolder(holder); mAppBarPanel = (AppBarPanelView)mStatusBarWindow.findViewById(R.id.appbar_panel); mAppBarPanel.setStatusBar(this); mNotificationPanel = (NotificationPanelView) mStatusBarWindow.findViewById(R.id.notification_panel); mNotificationPanel.setStatusBar(this); if (!ActivityManager.isHighEndGfx()) { mStatusBarWindow.setBackground(null); mNotificationPanel.setBackground(new FastColorDrawable(context.getResources().getColor( R.color.notification_panel_solid_background))); mAppBarPanel.setBackground(new FastColorDrawable(context.getResources().getColor( R.color.notification_panel_solid_background))); } if (ENABLE_HEADS_UP) { if(mContext.getResources().getConfiguration().enableMultiWindow()){ mHeadsUpNotificationView = (HeadsUpNotificationView) View.inflate(context, R.layout.heads_up_win, null); } else { mHeadsUpNotificationView = (HeadsUpNotificationView) View.inflate(context, R.layout.heads_up, null); } mHeadsUpNotificationView.setVisibility(View.GONE); mHeadsUpNotificationView.setBar(this); } if (MULTIUSER_DEBUG) { mNotificationPanelDebugText = (TextView) mNotificationPanel.findViewById( R.id.header_debug_info); mNotificationPanelDebugText.setVisibility(View.VISIBLE); } updateShowSearchHoldoff(); try { boolean showNav = mWindowManagerService.hasNavigationBar(); if (DEBUG) Log.v(TAG, "hasNavigationBar=" + showNav); if (showNav) { //haungjc:win bar if(mContext.getResources().getConfiguration().enableMultiWindow()){ mNavigationBarView = (NavigationBarView) View.inflate(mContext, R.layout.navigation_bar_win, null); }else{ mNavigationBarView = (NavigationBarView) View.inflate(mContext, R.layout.navigation_bar, null); } mNavigationBarView.setDisabledFlags(mDisabled); mNavigationBarView.setBar(this); mNavigationBarView.setOnVerticalChangedListener( new NavigationBarView.OnVerticalChangedListener() { @Override public void onVerticalChanged(boolean isVertical) { if (mSearchPanelView != null) { mSearchPanelView.setHorizontal(isVertical); } mNotificationPanel.setQsScrimEnabled(!isVertical); } }); mNavigationBarView.setOnTouchListener(new View.OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { checkUserAutohide(v, event); return false; }}); if(mContext.getResources().getConfiguration().enableMultiWindow()){ mNotificationLite = null;//new NotificationCenterLite(mContext); mCalendarDialog = new CalendarDialog(mContext); } } } catch (RemoteException ex) { // no window manager? good luck with that } // figure out which pixel-format to use for the status bar. mPixelFormat = PixelFormat.OPAQUE; mSystemIconArea = (LinearLayout) mStatusBarView.findViewById(R.id.system_icon_area); mSystemIcons = (LinearLayout) mStatusBarView.findViewById(R.id.system_icons); mStatusIcons = (LinearLayout)mStatusBarView.findViewById(R.id.statusIcons); mNotificationIconArea = mStatusBarView.findViewById(R.id.notification_icon_area_inner); mNotificationIcons = (IconMerger)mStatusBarView.findViewById(R.id.notificationIcons); mMoreIcon = mStatusBarView.findViewById(R.id.moreIcon); mNotificationIcons.setOverflowIndicator(mMoreIcon); mStatusBarContents = (LinearLayout)mStatusBarView.findViewById(R.id.status_bar_contents); mSimSwitchNotification = (LinearLayout) mStatusBarView.findViewById( R.id.simSwitchNotification); mSimSwitchNotificationText = (TextView) mStatusBarView.findViewById( R.id.simSwitchNotificationText); mSimSwitchContainer = (LinearLayout) mStatusBarWindow.findViewById( R.id.sim_switch_container); mSim1Container = (LinearLayout)mStatusBarWindow.findViewById(R.id.sim1_container); mSim2Container = (LinearLayout)mStatusBarWindow.findViewById(R.id.sim2_container); mAskContainer = (LinearLayout)mStatusBarWindow.findViewById(R.id.ask_container); mSwitchSim1Button = (ImageView)mStatusBarWindow.findViewById(R.id.sim1_switch_button); mSwitchSim2Button = (ImageView)mStatusBarWindow.findViewById(R.id.sim2_switch_button); mSwitchAskButton = (ImageView)mStatusBarWindow.findViewById(R.id.ask_switch_button); mSwitchSim1Button.setOnClickListener(mSimSwitchListener); mSwitchSim2Button.setOnClickListener(mSimSwitchListener); mSwitchAskButton.setOnClickListener(mSimSwitchListener); mStackScroller = (NotificationStackScrollLayout) mStatusBarWindow.findViewById( R.id.notification_stack_scroller); mStackScroller.setLongPressListener(getNotificationLongClicker()); mStackScroller.setPhoneStatusBar(this); mKeyguardIconOverflowContainer = (NotificationOverflowContainer) LayoutInflater.from(mContext).inflate( R.layout.status_bar_notification_keyguard_overflow, mStackScroller, false); mKeyguardIconOverflowContainer.setOnActivatedListener(this); mKeyguardIconOverflowContainer.setOnClickListener(mOverflowClickListener); mStackScroller.addView(mKeyguardIconOverflowContainer); SpeedBumpView speedBump = (SpeedBumpView) LayoutInflater.from(mContext).inflate( R.layout.status_bar_notification_speed_bump, mStackScroller, false); mStackScroller.setSpeedBumpView(speedBump); mEmptyShadeView = (EmptyShadeView) LayoutInflater.from(mContext).inflate( R.layout.status_bar_no_notifications, mStackScroller, false); mStackScroller.setEmptyShadeView(mEmptyShadeView); mDismissView = (DismissView) LayoutInflater.from(mContext).inflate( R.layout.status_bar_notification_dismiss_all, mStackScroller, false); mDismissView.setOnButtonClickListener(new View.OnClickListener() { @Override public void onClick(View v) { clearAllNotifications(); } }); mStackScroller.setDismissView(mDismissView); mExpandedContents = mStackScroller; mBackdrop = (BackDropView) mStatusBarWindow.findViewById(R.id.backdrop); mBackdropFront = (ImageView) mBackdrop.findViewById(R.id.backdrop_front); mBackdropBack = (ImageView) mBackdrop.findViewById(R.id.backdrop_back); ScrimView scrimBehind = (ScrimView) mStatusBarWindow.findViewById(R.id.scrim_behind); ScrimView scrimInFront = (ScrimView) mStatusBarWindow.findViewById(R.id.scrim_in_front); mScrimController = new ScrimController(scrimBehind, scrimInFront, mScrimSrcModeEnabled); mScrimController.setBackDropView(mBackdrop); mStatusBarView.setScrimController(mScrimController); mDozeScrimController = new DozeScrimController(mScrimController, context); mHeader = (StatusBarHeaderView) mStatusBarWindow.findViewById(R.id.header); mHeader.setActivityStarter(this); mKeyguardStatusBar = (KeyguardStatusBarView) mStatusBarWindow.findViewById(R.id.keyguard_header); mStatusIconsKeyguard = (LinearLayout) mKeyguardStatusBar.findViewById(R.id.statusIcons); mKeyguardStatusView = mStatusBarWindow.findViewById(R.id.keyguard_status_view); mKeyguardBottomArea = (KeyguardBottomAreaView) mStatusBarWindow.findViewById(R.id.keyguard_bottom_area); mKeyguardBottomArea.setActivityStarter(this); mKeyguardIndicationController = new KeyguardIndicationController(mContext, (KeyguardIndicationTextView) mStatusBarWindow.findViewById( R.id.keyguard_indication_text)); mKeyguardBottomArea.setKeyguardIndicationController(mKeyguardIndicationController); mTickerEnabled = res.getBoolean(R.bool.enable_ticker); if (mTickerEnabled) { final ViewStub tickerStub = (ViewStub) mStatusBarView.findViewById(R.id.ticker_stub); if (tickerStub != null) { mTickerView = tickerStub.inflate(); mTicker = new MyTicker(context, mStatusBarView); TickerView tickerView = (TickerView) mStatusBarView.findViewById(R.id.tickerText); tickerView.mTicker = mTicker; } } mEdgeBorder = res.getDimensionPixelSize(R.dimen.status_bar_edge_ignore); // set the inital view visibility setAreThereNotifications(); // Background thread for any controllers that need it. mHandlerThread = new HandlerThread(TAG, Process.THREAD_PRIORITY_BACKGROUND); mHandlerThread.start(); // Other icons mLocationController = new LocationControllerImpl(mContext); // will post a notification mBatteryController = new BatteryController(mContext); mBatteryController.setPercentageView((TextView) mStatusBarWindow.findViewById(R.id.battery_percentage)); mBatteryController.addStateChangedCallback(new BatteryStateChangeCallback() { @Override public void onPowerSaveChanged() { mHandler.post(mCheckBarModes); if (mDozeServiceHost != null) { mDozeServiceHost.firePowerSaveChanged(mBatteryController.isPowerSave()); } } @Override public void onBatteryLevelChanged(int level, boolean pluggedIn, boolean charging) { // noop } }); mNetworkController = new NetworkControllerImpl(mContext); mHotspotController = new HotspotControllerImpl(mContext); mBluetoothController = new BluetoothControllerImpl(mContext, mHandlerThread.getLooper()); mSecurityController = new SecurityControllerImpl(mContext); if (mContext.getResources().getBoolean(R.bool.config_showRotationLock)) { mRotationLockController = new RotationLockControllerImpl(mContext); } mUserInfoController = new UserInfoController(mContext); mVolumeComponent = getComponent(VolumeComponent.class); if (mVolumeComponent != null) { mZenModeController = mVolumeComponent.getZenController(); } mCastController = new CastControllerImpl(mContext); final SignalClusterView signalCluster = (SignalClusterView) mStatusBarView.findViewById(R.id.signal_cluster); final SignalClusterView signalClusterKeyguard = (SignalClusterView) mKeyguardStatusBar.findViewById(R.id.signal_cluster); final SignalClusterView signalClusterQs = (SignalClusterView) mHeader.findViewById(R.id.signal_cluster); mNetworkController.addSignalCluster(signalCluster); mNetworkController.addSignalCluster(signalClusterKeyguard); mNetworkController.addSignalCluster(signalClusterQs); signalCluster.setSecurityController(mSecurityController); signalCluster.setNetworkController(mNetworkController); signalClusterKeyguard.setSecurityController(mSecurityController); signalClusterKeyguard.setNetworkController(mNetworkController); signalClusterQs.setSecurityController(mSecurityController); signalClusterQs.setNetworkController(mNetworkController); if(mContext.getResources().getConfiguration().enableMultiWindow()){ if(signalCluster_win==null&&mNavigationBarView!=null){ mStatusIcons_win = mNavigationBarView.getStatusIcons_win(); signalCluster_win = (SignalClusterView) mNavigationBarView.findViewById(R.id.signal_cluster); mNetworkController.addSignalCluster(signalCluster_win); signalCluster_win.setSecurityController(mSecurityController); signalCluster_win.setNetworkController(mNetworkController); } } final boolean isAPhone = mNetworkController.hasVoiceCallingFeature(); if (isAPhone) { mNetworkController.addEmergencyListener(new NetworkControllerImpl.EmergencyListener() { @Override public void setEmergencyCallsOnly(boolean emergencyOnly) { mHeader.setShowEmergencyCallsOnly(emergencyOnly); } }); } mCarrierLabel = (TextView)mStatusBarWindow.findViewById(R.id.carrier_label); mShowCarrierInPanel = (mCarrierLabel != null); if (DEBUG) Log.v(TAG, "carrierlabel=" + mCarrierLabel + " show=" + mShowCarrierInPanel); if (mShowCarrierInPanel) { mCarrierLabel.setVisibility(mCarrierLabelVisible ? View.VISIBLE : View.INVISIBLE); mNetworkController.addCarrierLabel(new NetworkControllerImpl.CarrierLabelListener() { @Override public void setCarrierLabel(String label) { mCarrierLabel.setText(label); if (mNetworkController.hasMobileDataFeature()) { if (TextUtils.isEmpty(label)) { mCarrierLabel.setVisibility(View.GONE); } else { mCarrierLabel.setVisibility(View.VISIBLE); } } } }); } mFlashlightController = new FlashlightController(mContext); mKeyguardBottomArea.setFlashlightController(mFlashlightController); mKeyguardBottomArea.setPhoneStatusBar(this); mAccessibilityController = new AccessibilityController(mContext); mKeyguardBottomArea.setAccessibilityController(mAccessibilityController); mNextAlarmController = new NextAlarmController(mContext); mKeyguardMonitor = new KeyguardMonitor(); if (UserSwitcherController.isUserSwitcherAvailable(UserManager.get(mContext))) { mUserSwitcherController = new UserSwitcherController(mContext, mKeyguardMonitor); } mKeyguardUserSwitcher = new KeyguardUserSwitcher(mContext, (ViewStub) mStatusBarWindow.findViewById(R.id.keyguard_user_switcher), mKeyguardStatusBar, mNotificationPanel, mUserSwitcherController); // Set up the quick settings tile panel mQSPanel = (QSPanel) mStatusBarWindow.findViewById(R.id.quick_settings_panel); if (mQSPanel != null) { final QSTileHost qsh = new QSTileHost(mContext, this, mBluetoothController, mLocationController, mRotationLockController, mNetworkController, mZenModeController, mHotspotController, mCastController, mFlashlightController, mUserSwitcherController, mKeyguardMonitor, mSecurityController); mQSPanel.setHost(qsh); mQSPanel.setTiles(qsh.getTiles()); mBrightnessMirrorController = new BrightnessMirrorController(mStatusBarWindow); mQSPanel.setBrightnessMirror(mBrightnessMirrorController); mHeader.setQSPanel(mQSPanel); qsh.setCallback(new QSTileHost.Callback() { @Override public void onTilesChanged() { mQSPanel.setTiles(qsh.getTiles()); } }); } // User info. Trigger first load. mHeader.setUserInfoController(mUserInfoController); mKeyguardStatusBar.setUserInfoController(mUserInfoController); mUserInfoController.reloadUserInfo(); mHeader.setBatteryController(mBatteryController); ((BatteryMeterView) mStatusBarView.findViewById(R.id.battery)).setBatteryController( mBatteryController); //AnsonCode hide battery if(!mContext.getResources().getBoolean(R.bool.config_has_battery)){ mStatusBarView.findViewById(R.id.battery).setVisibility(View.GONE); } mKeyguardStatusBar.setBatteryController(mBatteryController); mHeader.setNextAlarmController(mNextAlarmController); PowerManager pm = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE); mBroadcastReceiver.onReceive(mContext, new Intent(pm.isScreenOn() ? Intent.ACTION_SCREEN_ON : Intent.ACTION_SCREEN_OFF)); // receive broadcasts IntentFilter filter = new IntentFilter(); filter.addAction(Intent.ACTION_CLOSE_SYSTEM_DIALOGS); filter.addAction(Intent.ACTION_SCREEN_OFF); filter.addAction(Intent.ACTION_SCREEN_ON); if (DEBUG_MEDIA_FAKE_ARTWORK) { filter.addAction("fake_artwork"); } filter.addAction(ACTION_DEMO); context.registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL, filter, null, null); // listen for USER_SETUP_COMPLETE setting (per-user) resetUserSetupObserver(); startGlyphRasterizeHack(); return mStatusBarView; }|-- frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowManager.java/** * Adds the status bar view to the window manager. * * @param statusBarView The view to add. * @param barHeight The height of the status bar in collapsed state. */ public void add(View statusBarView, int barHeight) { // Now that the status bar window encompasses the sliding panel and its // translucent backdrop, the entire thing is made TRANSLUCENT and is // hardware-accelerated. mLp = new WindowManager.LayoutParams( ViewGroup.LayoutParams.MATCH_PARENT, barHeight, WindowManager.LayoutParams.TYPE_STATUS_BAR, WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_TOUCHABLE_WHEN_WAKING | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH | WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS, PixelFormat.TRANSLUCENT); mLp.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED; mLp.gravity = Gravity.TOP; mLp.softInputMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE; mLp.setTitle("StatusBar"); mLp.packageName = mContext.getPackageName(); mStatusBarView = statusBarView; mBarHeight = barHeight; /**----注释即可不显示 ----**/ mWindowManager.addView(mStatusBarView, mLp); mLpChanged = new WindowManager.LayoutParams(); mLpChanged.copyFrom(mLp); }状态栏 和导航栏, 通过WindowManager.addView添加并显示.[扩展]去除状态栏的方式有1. 把状态栏高度设置为0;2. 删除 mWindowManager.addView(mStatusBarView, mLp);去除HEADS-UP通知显示在5.0后, android 增加了新的通知提示方式(HEADS-UP), 让用户能在任何界面(即使全屏)不会错过重要通知.Notification.Builder builder = new Notification.Builder(this); builder.setContentTitle("通知"); builder.setContentText("横幅提醒"); builder.setDefaults(Notification.DEFAULT_ALL); builder.setSmallIcon(R.mipmap.ic_launcher); builder.setLargeIcon(BitmapFactory.decodeResource(getResources(), R.mipmap.ic_launcher)); Intent intent = new Intent(this, EntranceActivity.class); PendingIntent pIntent = PendingIntent.getActivity(this, 1, intent, 0); builder.setContentIntent(pIntent); /**----重点----***/ builder.setFullScreenIntent(pIntent, true); builder.setAutoCancel(true);setFullScreenIntent 干了什么:|-- frameworks/base/core/java/android/app/Notification.javapublic Builder setFullScreenIntent(PendingIntent intent, boolean highPriority) { /**---- mFullScreenIntent赋了非空 ----**/ mFullScreenIntent = intent; setFlag(FLAG_HIGH_PRIORITY, highPriority); return this; }发送通知:|-- frameworks/base/services/core/java/com/android/server/notification/NotificationManagerService.java@Override public void enqueueNotificationWithTag(String pkg, String opPkg, String tag, int id, Notification notification, int[] idOut, int userId) throws RemoteException { enqueueNotificationInternal(pkg, opPkg, Binder.getCallingUid(), Binder.getCallingPid(), tag, id, notification, idOut, userId); } void enqueueNotificationInternal(final String pkg, final String opPkg, final int callingUid, final int callingPid, final String tag, final int id, final Notification notification, int[] idOut, int incomingUserId) { if (DBG) { Slog.v(TAG, "enqueueNotificationInternal: pkg=" + pkg + " id=" + id + " notification=" + notification); } checkCallerIsSystemOrSameApp(pkg); final boolean isSystemNotification = isUidSystem(callingUid) || ("android".equals(pkg)); final boolean isNotificationFromListener = mListeners.isListenerPackage(pkg); final int userId = ActivityManager.handleIncomingUser(callingPid, callingUid, incomingUserId, true, false, "enqueueNotification", pkg); final UserHandle user = new UserHandle(userId); // Limit the number of notifications that any given package except the android // package or a registered listener can enqueue. Prevents DOS attacks and deals with leaks. if (!isSystemNotification && !isNotificationFromListener) { synchronized (mNotificationList) { int count = 0; final int N = mNotificationList.size(); for (int i=0; i<N; i++) { final NotificationRecord r = mNotificationList.get(i); if (r.sbn.getPackageName().equals(pkg) && r.sbn.getUserId() == userId) { count++; if (count >= MAX_PACKAGE_NOTIFICATIONS) { Slog.e(TAG, "Package has already posted " + count + " notifications. Not showing more. package=" + pkg); return; } } } } } if (pkg == null || notification == null) { throw new IllegalArgumentException("null not allowed: pkg=" + pkg + " id=" + id + " notification=" + notification); } if (notification.icon != 0) { if (!notification.isValid()) { throw new IllegalArgumentException("Invalid notification (): pkg=" + pkg + " id=" + id + " notification=" + notification); } } mHandler.post(new Runnable() { @Override public void run() { synchronized (mNotificationList) { // === Scoring === // 0. Sanitize inputs notification.priority = clamp(notification.priority, Notification.PRIORITY_MIN, Notification.PRIORITY_MAX); // Migrate notification flags to scores if (0 != (notification.flags & Notification.FLAG_HIGH_PRIORITY)) { if (notification.priority < Notification.PRIORITY_MAX) { notification.priority = Notification.PRIORITY_MAX; } } else if (SCORE_ONGOING_HIGHER && 0 != (notification.flags & Notification.FLAG_ONGOING_EVENT)) { if (notification.priority < Notification.PRIORITY_HIGH) { notification.priority = Notification.PRIORITY_HIGH; } } // 1. initial score: buckets of 10, around the app [-20..20] final int score = notification.priority * NOTIFICATION_PRIORITY_MULTIPLIER; // 2. extract ranking signals from the notification data final StatusBarNotification n = new StatusBarNotification( pkg, opPkg, id, tag, callingUid, callingPid, score, notification, user); NotificationRecord r = new NotificationRecord(n, score); NotificationRecord old = mNotificationsByKey.get(n.getKey()); if (old != null) { // Retain ranking information from previous record r.copyRankingInformation(old); } // Handle grouped notifications and bail out early if we // can to avoid extracting signals. handleGroupedNotificationLocked(r, old, callingUid, callingPid); boolean ignoreNotification = removeUnusedGroupedNotificationLocked(r, old, callingUid, callingPid); // This conditional is a dirty hack to limit the logging done on // behalf of the download manager without affecting other apps. if (!pkg.equals("com.android.providers.downloads") || Log.isLoggable("DownloadManager", Log.VERBOSE)) { int enqueueStatus = EVENTLOG_ENQUEUE_STATUS_NEW; if (ignoreNotification) { enqueueStatus = EVENTLOG_ENQUEUE_STATUS_IGNORED; } else if (old != null) { enqueueStatus = EVENTLOG_ENQUEUE_STATUS_UPDATE; } EventLogTags.writeNotificationEnqueue(callingUid, callingPid, pkg, id, tag, userId, notification.toString(), enqueueStatus); } if (ignoreNotification) { return; } mRankingHelper.extractSignals(r); // 3. Apply local rules // blocked apps if (ENABLE_BLOCKED_NOTIFICATIONS && !noteNotificationOp(pkg, callingUid)) { if (!isSystemNotification) { r.score = JUNK_SCORE; Slog.e(TAG, "Suppressing notification from package " + pkg + " by user request."); } } if (r.score < SCORE_DISPLAY_THRESHOLD) { // Notification will be blocked because the score is too low. return; } int index = indexOfNotificationLocked(n.getKey()); if (index < 0) { mNotificationList.add(r); mUsageStats.registerPostedByApp(r); } else { old = mNotificationList.get(index); mNotificationList.set(index, r); mUsageStats.registerUpdatedByApp(r, old); // Make sure we don't lose the foreground service state. notification.flags |= old.getNotification().flags & Notification.FLAG_FOREGROUND_SERVICE; r.isUpdate = true; } mNotificationsByKey.put(n.getKey(), r); // Ensure if this is a foreground service that the proper additional // flags are set. if ((notification.flags & Notification.FLAG_FOREGROUND_SERVICE) != 0) { notification.flags |= Notification.FLAG_ONGOING_EVENT | Notification.FLAG_NO_CLEAR; } applyZenModeLocked(r); mRankingHelper.sort(mNotificationList); if (notification.icon != 0) { StatusBarNotification oldSbn = (old != null) ? old.sbn : null; mListeners.notifyPostedLocked(n, oldSbn); } else { Slog.e(TAG, "Not posting notification with icon==0: " + notification); if (old != null && !old.isCanceled) { mListeners.notifyRemovedLocked(n); } // ATTENTION: in a future release we will bail out here // so that we do not play sounds, show lights, etc. for invalid // notifications Slog.e(TAG, "WARNING: In a future release this will crash the app: " + n.getPackageName()); } buzzBeepBlinkLocked(r); } } }); idOut[0] = id; } /** * asynchronously notify all listeners about a new notification * * <p> * Also takes care of removing a notification that has been visible to a listener before, * but isn't anymore. */ public void notifyPostedLocked(StatusBarNotification sbn, StatusBarNotification oldSbn) { // Lazily initialized snapshots of the notification. StatusBarNotification sbnClone = null; StatusBarNotification sbnCloneLight = null; for (final ManagedServiceInfo info : mServices) { boolean sbnVisible = isVisibleToListener(sbn, info); boolean oldSbnVisible = oldSbn != null ? isVisibleToListener(oldSbn, info) : false; // This notification hasn't been and still isn't visible -> ignore. if (!oldSbnVisible && !sbnVisible) { continue; } final NotificationRankingUpdate update = makeRankingUpdateLocked(info); // This notification became invisible -> remove the old one. if (oldSbnVisible && !sbnVisible) { final StatusBarNotification oldSbnLightClone = oldSbn.cloneLight(); mHandler.post(new Runnable() { @Override public void run() { notifyRemoved(info, oldSbnLightClone, update); } }); continue; } final int trim = mListeners.getOnNotificationPostedTrim(info); if (trim == TRIM_LIGHT && sbnCloneLight == null) { sbnCloneLight = sbn.cloneLight(); } else if (trim == TRIM_FULL && sbnClone == null) { sbnClone = sbn.clone(); } final StatusBarNotification sbnToPost = (trim == TRIM_FULL) ? sbnClone : sbnCloneLight; mHandler.post(new Runnable() { @Override public void run() { notifyPosted(info, sbnToPost, update); } }); } } private void notifyPosted(final ManagedServiceInfo info, final StatusBarNotification sbn, NotificationRankingUpdate rankingUpdate) { final INotificationListener listener = (INotificationListener)info.service; StatusBarNotificationHolder sbnHolder = new StatusBarNotificationHolder(sbn); try { listener.onNotificationPosted(sbnHolder, rankingUpdate); } catch (RemoteException ex) { Log.e(TAG, "unable to notify listener (posted): " + listener, ex); } }|-- frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java/**---- 注册监听通知服务 ----**/ public void start() { // Set up the initial notification state. try { mNotificationListener.registerAsSystemService(mContext, new ComponentName(mContext.getPackageName(), getClass().getCanonicalName()), UserHandle.USER_ALL); } catch (RemoteException e) { Log.e(TAG, "Unable to register notification listener", e); } } |-- frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java ```java /**---- 注册监听通知服务 ----**/ public void start() { // Set up the initial notification state. try { mNotificationListener.registerAsSystemService(mContext, new ComponentName(mContext.getPackageName(), getClass().getCanonicalName()), UserHandle.USER_ALL); } catch (RemoteException e) { Log.e(TAG, "Unable to register notification listener", e); } } private final NotificationListenerService mNotificationListener = new NotificationListenerService() { @Override public void onListenerConnected() { if (DEBUG) Log.d(TAG, "onListenerConnected"); final StatusBarNotification[] notifications = getActiveNotifications(); final RankingMap currentRanking = getCurrentRanking(); mHandler.post(new Runnable() { @Override public void run() { for (StatusBarNotification sbn : notifications) { addNotification(sbn, currentRanking); } } }); } /**---- 由 NotificationManagerService 调用 ----**/ @Override public void onNotificationPosted(final StatusBarNotification sbn, final RankingMap rankingMap) { if (DEBUG) Log.d(TAG, "onNotificationPosted: " + sbn); mHandler.post(new Runnable() { @Override public void run() { Notification n = sbn.getNotification(); boolean isUpdate = mNotificationData.get(sbn.getKey()) != null || isHeadsUp(sbn.getKey()); // Ignore children of notifications that have a summary, since we're not // going to show them anyway. This is true also when the summary is canceled, // because children are automatically canceled by NoMan in that case. if (n.isGroupChild() && mNotificationData.isGroupWithSummary(sbn.getGroupKey())) { if (DEBUG) { Log.d(TAG, "Ignoring group child due to existing summary: " + sbn); } // Remove existing notification to avoid stale data. if (isUpdate) { removeNotification(sbn.getKey(), rankingMap); } else { mNotificationData.updateRanking(rankingMap); } return; } if (isUpdate) { updateNotification(sbn, rankingMap); } else { addNotification(sbn, rankingMap); } } }); } @Override public void onNotificationRemoved(final StatusBarNotification sbn, final RankingMap rankingMap) { if (DEBUG) Log.d(TAG, "onNotificationRemoved: " + sbn); mHandler.post(new Runnable() { @Override public void run() { removeNotification(sbn.getKey(), rankingMap); } }); } @Override public void onNotificationRankingUpdate(final RankingMap rankingMap) { if (DEBUG) Log.d(TAG, "onRankingUpdate"); mHandler.post(new Runnable() { @Override public void run() { updateNotificationRanking(rankingMap); } }); } };|-- frameworks/base/core/java/android/service/notification/NotificationListenerService.java /** * Directly register this service with the Notification Manager. * * <p>Only system services may use this call. It will fail for non-system callers. * Apps should ask the user to add their listener in Settings. * * @param context Context required for accessing resources. Since this service isn't * launched as a real Service when using this method, a context has to be passed in. * @param componentName the component that will consume the notification information * @param currentUser the user to use as the stream filter * @hide */ @SystemApi public void registerAsSystemService(Context context, ComponentName componentName, int currentUser) throws RemoteException { mSystemContext = context; if (mWrapper == null) { mWrapper = new INotificationListenerWrapper(); } INotificationManager noMan = getNotificationInterface(); noMan.registerListener(mWrapper, componentName, currentUser); mCurrentUser = currentUser; }|-- frameworks/base/services/core/java/com/android/server/notification/NotificationManagerService.java/** * Register a listener binder directly with the notification manager. * * Only works with system callers. Apps should extend * {@link android.service.notification.NotificationListenerService}. */ @Override public void registerListener(final INotificationListener listener, final ComponentName component, final int userid) { enforceSystemOrSystemUI("INotificationManager.registerListener"); mListeners.registerService(listener, component, userid); }收到通知后的处理:|-- frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java@Override public void addNotification(StatusBarNotification notification, RankingMap ranking) { if (DEBUG) Log.d(TAG, "addNotification key=" + notification.getKey()); if (mUseHeadsUp && shouldInterrupt(notification)) { if (DEBUG) Log.d(TAG, "launching notification in heads up mode"); Entry interruptionCandidate = new Entry(notification, null); ViewGroup holder = mHeadsUpNotificationView.getHolder(); if (inflateViewsForHeadsUp(interruptionCandidate, holder)) { /**---- 只需注释掉, 即可阻止显示HEADS-UP 通知 ---- **/ // 1. Populate mHeadsUpNotificationView mHeadsUpNotificationView.showNotification(interruptionCandidate); // do not show the notification in the shade, yet. return; } } Entry shadeEntry = createNotificationViews(notification); if (shadeEntry == null) { return; } if (notification.getNotification().fullScreenIntent != null) { // Stop screensaver if the notification has a full-screen intent. // (like an incoming phone call) awakenDreams(); // not immersive & a full-screen alert should be shown if (DEBUG) Log.d(TAG, "Notification has fullScreenIntent; sending fullScreenIntent"); try { EventLog.writeEvent(EventLogTags.SYSUI_FULLSCREEN_NOTIFICATION, notification.getKey()); notification.getNotification().fullScreenIntent.send(); } catch (PendingIntent.CanceledException e) { } } else { // usual case: status bar visible & not immersive // show the ticker if there isn't already a heads up if (mHeadsUpNotificationView.getEntry() == null) { tick(notification, true); } } addNotificationViews(shadeEntry, ranking); // Recalculate the position of the sliding windows and the titles. setAreThereNotifications(); updateExpandedViewPos(EXPANDED_LEAVE_ALONE); }|-- frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java protected boolean shouldInterrupt(StatusBarNotification sbn) { if (mNotificationData.shouldFilterOut(sbn)) { if (DEBUG) { Log.d(TAG, "Skipping HUN check for " + sbn.getKey() + " since it's filtered out."); } return false; } if ((null!=mHeadsUpNotificationView)&&mHeadsUpNotificationView.isSnoozed(sbn.getPackageName())) { return false; } Notification notification = sbn.getNotification(); // some predicates to make the boolean logic legible boolean isNoisy = (notification.defaults & Notification.DEFAULT_SOUND) != 0 || (notification.defaults & Notification.DEFAULT_VIBRATE) != 0 || notification.sound != null || notification.vibrate != null; boolean isHighPriority = sbn.getScore() >= INTERRUPTION_THRESHOLD; /**---- 前面已设置非空 ----**/ boolean isFullscreen = notification.fullScreenIntent != null; boolean hasTicker = mHeadsUpTicker && !TextUtils.isEmpty(notification.tickerText); boolean isAllowed = notification.extras.getInt(Notification.EXTRA_AS_HEADS_UP, Notification.HEADS_UP_ALLOWED) != Notification.HEADS_UP_NEVER; boolean accessibilityForcesLaunch = isFullscreen && mAccessibilityManager.isTouchExplorationEnabled(); if(mContext.getResources().getConfiguration().enableMultiWindow()&&!isFullscreen) isFullscreen = true&&!sbn.isOngoing(); boolean interrupt = (isFullscreen || (isHighPriority && (isNoisy || hasTicker))) && isAllowed && !accessibilityForcesLaunch && mPowerManager.isScreenOn() && (!mStatusBarKeyguardViewManager.isShowing() || mStatusBarKeyguardViewManager.isOccluded()) && !mStatusBarKeyguardViewManager.isInputRestricted(); try { interrupt = interrupt && !mDreamManager.isDreaming(); } catch (RemoteException e) { Log.d(TAG, "failed to query dream manager", e); } if (DEBUG) Log.d(TAG, "interrupt: " + interrupt); return interrupt; }|-- frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpNotificationView.javapublic boolean showNotification(NotificationData.Entry headsUp) { if (mHeadsUp != null && headsUp != null && !mHeadsUp.key.equals(headsUp.key)) { // bump any previous heads up back to the shade release(); } mHeadsUp = headsUp; if (mContentHolder != null) { mContentHolder.removeAllViews(); } if (mHeadsUp != null) { mMostRecentPackageName = mHeadsUp.notification.getPackageName(); mHeadsUp.row.setSystemExpanded(true); mHeadsUp.row.setSensitive(false); mHeadsUp.row.setHeadsUp(true); mHeadsUp.row.setHideSensitive( false, false /* animated */, 0 /* delay */, 0 /* duration */); if (mContentHolder == null) { // too soon! return false; } mContentHolder.setX(0); mContentHolder.setVisibility(View.VISIBLE); mContentHolder.setAlpha(mMaxAlpha); mContentHolder.addView(mHeadsUp.row); sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED); mSwipeHelper.snapChild(mContentHolder, 1f); mStartTouchTime = SystemClock.elapsedRealtime() + mTouchSensitivityDelay; mHeadsUp.setInterruption(); // 2. Animate mHeadsUpNotificationView in mBar.scheduleHeadsUpOpen(); // 3. Set alarm to age the notification off mBar.resetHeadsUpDecayTimer(); } return true; }通知长按处理通知VIEW结构:|-- frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java |-- frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java |-- frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java ... * NExpandableNotificationRow 的父类关系:ExpandableNotificationRow -> ActivatableNotificationView -> ExpandableOutlineView -> ExpandableView -> FrameLayout长按事件实际是由NotificationStackScrollLayout处理的:|-- frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java public void setLongPressListener(SwipeHelper.LongPressListener listener) { mSwipeHelper.setLongPressListener(listener); mLongPressListener = listener; }|-- frameworks/base/packages/SystemUI/src/com/android/systemui/SwipeHelper.javapublic void setLongPressListener(LongPressListener listener) { mLongPressListener = listener; } public boolean onInterceptTouchEvent(final MotionEvent ev) { final int action = ev.getAction(); switch (action) { case MotionEvent.ACTION_DOWN: mTouchAboveFalsingThreshold = false; mDragging = false; mLongPressSent = false; mCurrView = mCallback.getChildAtPosition(ev); mVelocityTracker.clear(); if (mCurrView != null) { mCurrAnimView = mCallback.getChildContentView(mCurrView); mCanCurrViewBeDimissed = mCallback.canChildBeDismissed(mCurrView); mVelocityTracker.addMovement(ev); mInitialTouchPos = getPos(ev); if (mLongPressListener != null) { if (mWatchLongPress == null) { mWatchLongPress = new Runnable() { @Override public void run() { if (mCurrView != null && !mLongPressSent) { mLongPressSent = true; mCurrView.sendAccessibilityEvent( AccessibilityEvent.TYPE_VIEW_LONG_CLICKED); mCurrView.getLocationOnScreen(mTmpPos); final int x = (int) ev.getRawX() - mTmpPos[0]; final int y = (int) ev.getRawY() - mTmpPos[1]; mLongPressListener.onLongPress(mCurrView, x, y); } } }; } mHandler.postDelayed(mWatchLongPress, mLongPressTimeout); } } break; ... }长按的监听由PhoneStatusBar传入:|-- frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.javaprotected PhoneStatusBarView makeStatusBarView() { final Context context = mContext; IntentFilter intentfilter=new IntentFilter(); intentfilter.addAction("rk.android.screenshot.SHOW"); intentfilter.addAction("rk.android.screenshot.ACTION"); context.registerReceiver(receiver, intentfilter); ... mStackScroller = (NotificationStackScrollLayout) mStatusBarWindow.findViewById( R.id.notification_stack_scroller); mStackScroller.setLongPressListener(getNotificationLongClicker()); mStackScroller.setPhoneStatusBar(this); }|-- frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.javaprotected SwipeHelper.LongPressListener getNotificationLongClicker() { return new SwipeHelper.LongPressListener() { @Override public boolean onLongPress(View v, int x, int y) { /**---- 若不希望处理长按, 则可直接返回结果, 或不注册长按监听即可 ----**/ dismissPopups(); if (!(v instanceof ExpandableNotificationRow)) { return false; } if (v.getWindowToken() == null) { Log.e(TAG, "Trying to show notification guts, but not attached to window"); return false; } inflateGuts((ExpandableNotificationRow) v); // Assume we are a status_bar_notification_row final NotificationGuts guts = (NotificationGuts) v.findViewById( R.id.notification_guts); if (guts == null) { // This view has no guts. Examples are the more card or the dismiss all view return false; } // Already showing? if (guts.getVisibility() == View.VISIBLE) { Log.e(TAG, "Trying to show notification guts, but already visible"); return false; } guts.setVisibility(View.VISIBLE); final double horz = Math.max(guts.getWidth() - x, x); final double vert = Math.max(guts.getActualHeight() - y, y); final float r = (float) Math.hypot(horz, vert); final Animator a = ViewAnimationUtils.createCircularReveal(guts, x, y, 0, r); a.setDuration(400); a.setInterpolator(mLinearOutSlowIn); a.start(); mNotificationGutsExposed = guts; return true; } }; }
Chrome方法已废弃后续测试, Chrome已经无法使用此方法, 也找不到当初对应测试的版本Google Chrome app is no longer the WebView provider in Android 10后续采用Google WebView, 改法参照下文<webviewproviders> <!-- The default WebView implementation --> <webviewprovider description="Android WebView" packageName="com.android.webview" availableByDefault="true"> </webviewprovider> <webviewprovider description="Google WebView" packageName="com.google.android.webview" availableByDefault="false"> </webviewprovider> </webviewproviders>平台RK3288 + Android 7.1说明选项位置: 设置 > 开发者选项 > WebView实现1.在Pixel上, 可以显示两个选项: Android System WebView 和 Chrome尝试把Chorme 禁用后, 选项中, 仅剩下Android System WebView.2.尝试在RK3288主板上安装Chrome, 并增加相应配置<webviewprovider description="Chrome WebView X" packageName="com.android.chrome" availableByDefault="true"> </webviewprovider>编译烧录后, 可以看到, 新增了Chrome WebView X, 测试选择不同的实现方法, 均可正常使用.为确认装入Chrome后可以生效, 已删除源码自带/system/app/webview相关源码|-- packages/apps/Settings/src/com/android/settings/DevelopmentSettings.java@Override public void onCreate(Bundle icicle) { super.onCreate(icicle); mWindowManager = IWindowManager.Stub.asInterface(ServiceManager.getService("window")); mBackupManager = IBackupManager.Stub.asInterface( ServiceManager.getService(Context.BACKUP_SERVICE)); //获取 IWebViewUpdateService mWebViewUpdateService = IWebViewUpdateService.Stub.asInterface(ServiceManager.getService("webviewupdate")); ... } private void updateWebViewProviderOptions() { try { // 从IWebViewUpdateService中获取可用的WebView 包名, 并填充列表. WebViewProviderInfo[] providers = mWebViewUpdateService.getValidWebViewPackages(); if (providers == null) { Log.e(TAG, "No WebView providers available"); return; } ArrayList<String> options = new ArrayList<String>(); ArrayList<String> values = new ArrayList<String>(); for(int n = 0; n < providers.length; n++) { if (Utils.isPackageEnabled(getActivity(), providers[n].packageName)) { options.add(providers[n].description); values.add(providers[n].packageName); } } mWebViewProvider.setEntries(options.toArray(new String[options.size()])); mWebViewProvider.setEntryValues(values.toArray(new String[values.size()])); String value = mWebViewUpdateService.getCurrentWebViewPackageName(); if (value == null) { value = ""; } for (int i = 0; i < values.size(); i++) { if (value.contentEquals(values.get(i))) { mWebViewProvider.setValueIndex(i); return; } } } catch(RemoteException e) { } }|-- frameworks/base/services/core/java/com/android/server/webkit/WebViewUpdateServiceImpl.javapublic WebViewUpdateServiceImpl(Context context, SystemInterface systemInterface) { mContext = context; mSystemInterface = systemInterface; mWebViewUpdater = new WebViewUpdater(mContext, mSystemInterface); } WebViewProviderInfo[] getValidWebViewPackages() { return mWebViewUpdater.getValidAndInstalledWebViewPackages(); } private static class WebViewUpdater { private ProviderAndPackageInfo[] getValidWebViewPackagesAndInfos(boolean onlyInstalled) { WebViewProviderInfo[] allProviders = mSystemInterface.getWebViewPackages(); List<ProviderAndPackageInfo> providers = new ArrayList<>(); for(int n = 0; n < allProviders.length; n++) { try { PackageInfo packageInfo = mSystemInterface.getPackageInfoForProvider(allProviders[n]); if ((!onlyInstalled || isInstalledPackage(packageInfo)) && isValidProvider(allProviders[n], packageInfo)) { providers.add(new ProviderAndPackageInfo(allProviders[n], packageInfo)); } } catch (NameNotFoundException e) { // Don't add non-existent packages } } return providers.toArray(new ProviderAndPackageInfo[providers.size()]); } }|-- frameworks/base/services/core/java/com/android/server/webkit/WebViewUpdateService.javapublic WebViewUpdateService(Context context) { super(context); mImpl = new WebViewUpdateServiceImpl(context, SystemImpl.getInstance()); }|-- frameworks/base/services/core/java/com/android/server/webkit/SystemInterface.javapublic class SystemImpl implements SystemInterface { ... private final WebViewProviderInfo[] mWebViewProviderPackages; // Initialization-on-demand holder idiom for getting the WebView provider packages once and // for all in a thread-safe manner. private static class LazyHolder { private static final SystemImpl INSTANCE = new SystemImpl(); } public static SystemImpl getInstance() { return LazyHolder.INSTANCE; } private SystemImpl() { int numFallbackPackages = 0; int numAvailableByDefaultPackages = 0; int numAvByDefaultAndNotFallback = 0; XmlResourceParser parser = null; List<WebViewProviderInfo> webViewProviders = new ArrayList<WebViewProviderInfo>(); try { //读取系统配置文件config_webview_packages.xml中的值: parser = AppGlobals.getInitialApplication().getResources().getXml( com.android.internal.R.xml.config_webview_packages); XmlUtils.beginDocument(parser, TAG_START); while(true) { XmlUtils.nextElement(parser); String element = parser.getName(); if (element == null) { break; } if (element.equals(TAG_WEBVIEW_PROVIDER)) { String packageName = parser.getAttributeValue(null, TAG_PACKAGE_NAME); if (packageName == null) { throw new AndroidRuntimeException( "WebView provider in framework resources missing package name"); } String description = parser.getAttributeValue(null, TAG_DESCRIPTION); if (description == null) { throw new AndroidRuntimeException( "WebView provider in framework resources missing description"); } boolean availableByDefault = "true".equals( parser.getAttributeValue(null, TAG_AVAILABILITY)); boolean isFallback = "true".equals( parser.getAttributeValue(null, TAG_FALLBACK)); WebViewProviderInfo currentProvider = new WebViewProviderInfo( packageName, description, availableByDefault, isFallback, readSignatures(parser)); if (currentProvider.isFallback) { numFallbackPackages++; if (!currentProvider.availableByDefault) { throw new AndroidRuntimeException( "Each WebView fallback package must be available by default."); } if (numFallbackPackages > 1) { throw new AndroidRuntimeException( "There can be at most one WebView fallback package."); } } if (currentProvider.availableByDefault) { numAvailableByDefaultPackages++; if (!currentProvider.isFallback) { numAvByDefaultAndNotFallback++; } } webViewProviders.add(currentProvider); } else { Log.e(TAG, "Found an element that is not a WebView provider"); } } } catch (XmlPullParserException | IOException e) { throw new AndroidRuntimeException("Error when parsing WebView config " + e); } finally { if (parser != null) parser.close(); } if (numAvailableByDefaultPackages == 0) { throw new AndroidRuntimeException("There must be at least one WebView package " + "that is available by default"); } if (numAvByDefaultAndNotFallback == 0) { throw new AndroidRuntimeException("There must be at least one WebView package " + "that is available by default and not a fallback"); } mWebViewProviderPackages = webViewProviders.toArray(new WebViewProviderInfo[webViewProviders.size()]); }|-- frameworks/base/core/res/res/xml/config_webview_packages.xml<?xml version="1.0" encoding="utf-8"?> <!-- Copyright 2015 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. --> <webviewproviders> <!-- The default WebView implementation --> <webviewprovider description="Android WebView" packageName="com.android.webview" availableByDefault="true"> </webviewprovider> </webviewproviders>扩展|-- frameworks/base/core/java/android/webkit/WebView.javaprivate WebViewProvider mProvider; protected WebView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes, Map<String, Object> javaScriptInterfaces, boolean privateBrowsing) { super(context, attrs, defStyleAttr, defStyleRes); if (context == null) { throw new IllegalArgumentException("Invalid context argument"); } sEnforceThreadChecking = context.getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.JELLY_BEAN_MR2; checkThread(); ensureProviderCreated(); mProvider.init(javaScriptInterfaces, privateBrowsing); // Post condition of creating a webview is the CookieSyncManager.getInstance() is allowed. CookieSyncManager.setGetInstanceIsAllowed(); } private void ensureProviderCreated() { checkThread(); if (mProvider == null) { // As this can get called during the base class constructor chain, pass the minimum // number of dependencies here; the rest are deferred to init(). mProvider = getFactory().createWebView(this, new PrivateAccess()); } } private static synchronized WebViewFactoryProvider getFactory() { return WebViewFactory.getProvider(); } //加载网址 public void loadUrl(String url, Map<String, String> additionalHttpHeaders) { checkThread(); mProvider.loadUrl(url, additionalHttpHeaders); }|-- frameworks/base/core/java/android/webkit/WebViewFactory.java static WebViewFactoryProvider getProvider() { synchronized (sProviderLock) { ... try { Class<WebViewFactoryProvider> providerClass = getProviderClass(); try { sProviderInstance = providerClass.getConstructor(WebViewDelegate.class) .newInstance(new WebViewDelegate()); if (DEBUG) Log.v(LOGTAG, "Loaded provider: " + sProviderInstance); return sProviderInstance; } catch (Exception e) { ... } } finally { Trace.traceEnd(Trace.TRACE_TAG_WEBVIEW); StrictMode.setThreadPolicy(oldPolicy); } } } private static Class<WebViewFactoryProvider> getProviderClass() { Context webViewContext = null; Application initialApplication = AppGlobals.getInitialApplication(); try { try { webViewContext = getWebViewContextAndSetProvider(); } finally { Trace.traceEnd(Trace.TRACE_TAG_WEBVIEW); } Log.i(LOGTAG, "Loading " + sPackageInfo.packageName + " version " + sPackageInfo.versionName + " (code " + sPackageInfo.versionCode + ")"); Trace.traceBegin(Trace.TRACE_TAG_WEBVIEW, "WebViewFactory.getChromiumProviderClass()"); try { initialApplication.getAssets().addAssetPathAsSharedLibrary( webViewContext.getApplicationInfo().sourceDir); ClassLoader clazzLoader = webViewContext.getClassLoader(); Trace.traceBegin(Trace.TRACE_TAG_WEBVIEW, "WebViewFactory.loadNativeLibrary()"); loadNativeLibrary(clazzLoader); Trace.traceEnd(Trace.TRACE_TAG_WEBVIEW); Trace.traceBegin(Trace.TRACE_TAG_WEBVIEW, "Class.forName()"); try { return (Class<WebViewFactoryProvider>) Class.forName(CHROMIUM_WEBVIEW_FACTORY, true, clazzLoader); } finally { Trace.traceEnd(Trace.TRACE_TAG_WEBVIEW); } } catch (ClassNotFoundException e) { Log.e(LOGTAG, "error loading provider", e); throw new AndroidRuntimeException(e); } finally { Trace.traceEnd(Trace.TRACE_TAG_WEBVIEW); } } catch (MissingWebViewPackageException e) { // If the package doesn't exist, then try loading the null WebView instead. // If that succeeds, then this is a device without WebView support; if it fails then // swallow the failure, complain that the real WebView is missing and rethrow the // original exception. try { return (Class<WebViewFactoryProvider>) Class.forName(NULL_WEBVIEW_FACTORY); } catch (ClassNotFoundException e2) { // Ignore. } Log.e(LOGTAG, "Chromium WebView package does not exist", e); throw new AndroidRuntimeException(e); } } private static Context getWebViewContextAndSetProvider() { Application initialApplication = AppGlobals.getInitialApplication(); try { WebViewProviderResponse response = null; try { //IWebViewUpdateService response = getUpdateService().waitForAndGetProvider(); } finally { Trace.traceEnd(Trace.TRACE_TAG_WEBVIEW); } ... try { ActivityManagerNative.getDefault().addPackageDependency( response.packageInfo.packageName); } finally { Trace.traceEnd(Trace.TRACE_TAG_WEBVIEW); } // Fetch package info and verify it against the chosen package PackageInfo newPackageInfo = null; try { newPackageInfo = initialApplication.getPackageManager().getPackageInfo( response.packageInfo.packageName, PackageManager.GET_SHARED_LIBRARY_FILES | PackageManager.MATCH_DEBUG_TRIAGED_MISSING // Make sure that we fetch the current provider even if its not // installed for the current user | PackageManager.MATCH_UNINSTALLED_PACKAGES // Fetch signatures for verification | PackageManager.GET_SIGNATURES // Get meta-data for meta data flag verification | PackageManager.GET_META_DATA); } finally { Trace.traceEnd(Trace.TRACE_TAG_WEBVIEW); } // Validate the newly fetched package info, throws MissingWebViewPackageException on // failure verifyPackageInfo(response.packageInfo, newPackageInfo); Trace.traceBegin(Trace.TRACE_TAG_WEBVIEW, "initialApplication.createApplicationContext"); try { // Construct an app context to load the Java code into the current app. Context webViewContext = initialApplication.createApplicationContext( newPackageInfo.applicationInfo, Context.CONTEXT_INCLUDE_CODE | Context.CONTEXT_IGNORE_SECURITY); sPackageInfo = newPackageInfo; return webViewContext; } finally { Trace.traceEnd(Trace.TRACE_TAG_WEBVIEW); } } catch (RemoteException | PackageManager.NameNotFoundException e) { throw new MissingWebViewPackageException("Failed to load WebView provider: " + e); } } /** @hide */ public static IWebViewUpdateService getUpdateService() { return IWebViewUpdateService.Stub.asInterface( ServiceManager.getService(WEBVIEW_UPDATE_SERVICE_NAME)); }
平台:rk3288 + android 7.1Android 对广播有明显的限定权限:系统应用仅发送指定受保护广播.E/ActivityManager: Sending non-protected broadcast android.intent.action.NEW_BROADCAST from system 1437:com.android.shell/2000 pkg com.android.shell java.lang.Throwable at com.android.server.am.ActivityManagerService.checkBroadcastFromSystem(ActivityManagerService.java:18169) at com.android.server.am.ActivityManagerService.broadcastIntentLocked(ActivityManagerService.java:18651) at com.android.server.am.ActivityManagerService.broadcastIntent(ActivityManagerService.java:18833) at android.app.ActivityManagerNative.onTransact(ActivityManagerNative.java:499) at com.android.server.am.ActivityManagerService.onTransact(ActivityManagerService.java:2911) at android.os.Binder.execTransact(Binder.java:565)相关源码:|-- frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java private void checkBroadcastFromSystem(Intent intent, ProcessRecord callerApp, String callerPackage, int callingUid, boolean isProtectedBroadcast, List receivers) { final String action = intent.getAction(); if (isProtectedBroadcast || Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(action) || Intent.ACTION_DISMISS_KEYBOARD_SHORTCUTS.equals(action) || Intent.ACTION_MEDIA_BUTTON.equals(action) || Intent.ACTION_MEDIA_SCANNER_SCAN_FILE.equals(action) || Intent.ACTION_SHOW_KEYBOARD_SHORTCUTS.equals(action) || Intent.ACTION_MASTER_CLEAR.equals(action) || AppWidgetManager.ACTION_APPWIDGET_CONFIGURE.equals(action) || AppWidgetManager.ACTION_APPWIDGET_UPDATE.equals(action) || LocationManager.HIGH_POWER_REQUEST_CHANGE_ACTION.equals(action) || TelephonyIntents.ACTION_REQUEST_OMADM_CONFIGURATION_UPDATE.equals(action) || SuggestionSpan.ACTION_SUGGESTION_PICKED.equals(action)) { // Broadcast is either protected, or it's a public action that // we've relaxed, so it's fine for system internals to send. return; } // This broadcast may be a problem... but there are often system components that // want to send an internal broadcast to themselves, which is annoying to have to // explicitly list each action as a protected broadcast, so we will check for that // one safe case and allow it: an explicit broadcast, only being received by something // that has protected itself. if (receivers != null && receivers.size() > 0 && (intent.getPackage() != null || intent.getComponent() != null)) { boolean allProtected = true; for (int i = receivers.size()-1; i >= 0; i--) { Object target = receivers.get(i); if (target instanceof ResolveInfo) { ResolveInfo ri = (ResolveInfo)target; if (ri.activityInfo.exported && ri.activityInfo.permission == null) { allProtected = false; break; } } else { BroadcastFilter bf = (BroadcastFilter)target; if (bf.requiredPermission == null) { allProtected = false; break; } } } if (allProtected) { // All safe! return; } } // The vast majority of broadcasts sent from system internals // should be protected to avoid security holes, so yell loudly // to ensure we examine these cases. if (callerApp != null) { Log.wtf(TAG, "Sending non-protected broadcast " + action + " from system " + callerApp.toShortString() + " pkg " + callerPackage, new Throwable()); } else { Log.wtf(TAG, "Sending non-protected broadcast " + action + " from system uid " + UserHandle.formatUid(callingUid) + " pkg " + callerPackage, new Throwable()); } } 广播还是可以发出去的, 只是会有LOG提示, 不影响实际功能.不允许第三方应用发送受保护广播非系统APK 发送了系统广播:Process: com.androidtest, PID: 1640 java.lang.RuntimeException: Unable to start activity ComponentInfo{com.androidtest/com.androidtest.MainActivity}: java.lang.SecurityException: Permission Denial: not allowed to send broadcast android.intent.action.NEW_BROADCAST from pid=1640, uid=10056 at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2671) at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2732) at android.app.ActivityThread.-wrap12(ActivityThread.java) at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1483) at android.os.Handler.dispatchMessage(Handler.java:102) at android.os.Looper.loop(Looper.java:154) at android.app.ActivityThread.main(ActivityThread.java:6141) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:912) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:802) Caused by: java.lang.SecurityException: Permission Denial: not allowed to send broadcast android.intent.action.NEW_BROADCAST from pid=1640, uid=10056 at android.os.Parcel.readException(Parcel.java:1684) at android.os.Parcel.readException(Parcel.java:1637) at android.app.ActivityManagerProxy.broadcastIntent(ActivityManagerNative.java:3565) at android.app.ContextImpl.sendBroadcast(ContextImpl.java:881) at android.content.ContextWrapper.sendBroadcast(ContextWrapper.java:421) at com.androidtest.MainActivity.testBroadcast(MainActivity.java:131) at com.androidtest.MainActivity.onCreate(MainActivity.java:41) at android.app.Activity.performCreate(Activity.java:6709) at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1118) at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2624) at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2732) at android.app.ActivityThread.-wrap12(ActivityThread.java) at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1483) at android.os.Handler.dispatchMessage(Handler.java:102) at android.os.Looper.loop(Looper.java:154) at android.app.ActivityThread.main(ActivityThread.java:6141) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:912) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:802)异常代码:|-- frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java final int broadcastIntentLocked(ProcessRecord callerApp, String callerPackage, Intent intent, String resolvedType, IIntentReceiver resultTo, int resultCode, String resultData, Bundle resultExtras, String[] requiredPermissions, int appOp, Bundle bOptions, boolean ordered, boolean sticky, int callingPid, int callingUid, int userId) { intent = new Intent(intent); // By default broadcasts do not go to stopped apps. intent.addFlags(Intent.FLAG_EXCLUDE_STOPPED_PACKAGES); // If we have not finished booting, don't allow this to launch new processes. if (!mProcessesReady && (intent.getFlags()&Intent.FLAG_RECEIVER_BOOT_UPGRADE) == 0) { intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY); } if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG_BROADCAST, (sticky ? "Broadcast sticky: ": "Broadcast: ") + intent + " ordered=" + ordered + " userid=" + userId); if ((resultTo != null) && !ordered) { Slog.w(TAG, "Broadcast " + intent + " not ordered but result callback requested!"); } userId = mUserController.handleIncomingUser(callingPid, callingUid, userId, true, ALLOW_NON_FULL, "broadcast", callerPackage); // Make sure that the user who is receiving this broadcast is running. // If not, we will just skip it. Make an exception for shutdown broadcasts // and upgrade steps. if (userId != UserHandle.USER_ALL && !mUserController.isUserRunningLocked(userId, 0)) { if ((callingUid != Process.SYSTEM_UID || (intent.getFlags() & Intent.FLAG_RECEIVER_BOOT_UPGRADE) == 0) && !Intent.ACTION_SHUTDOWN.equals(intent.getAction())) { Slog.w(TAG, "Skipping broadcast of " + intent + ": user " + userId + " is stopped"); return ActivityManager.BROADCAST_FAILED_USER_STOPPED; } } BroadcastOptions brOptions = null; if (bOptions != null) { brOptions = new BroadcastOptions(bOptions); if (brOptions.getTemporaryAppWhitelistDuration() > 0) { // See if the caller is allowed to do this. Note we are checking against // the actual real caller (not whoever provided the operation as say a // PendingIntent), because that who is actually supplied the arguments. if (checkComponentPermission( android.Manifest.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST, Binder.getCallingPid(), Binder.getCallingUid(), -1, true) != PackageManager.PERMISSION_GRANTED) { String msg = "Permission Denial: " + intent.getAction() + " broadcast from " + callerPackage + " (pid=" + callingPid + ", uid=" + callingUid + ")" + " requires " + android.Manifest.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST; Slog.w(TAG, msg); throw new SecurityException(msg); } } } // Verify that protected broadcasts are only being sent by system code, // and that system code is only sending protected broadcasts. final String action = intent.getAction(); final boolean isProtectedBroadcast; try { isProtectedBroadcast = AppGlobals.getPackageManager().isProtectedBroadcast(action); } catch (RemoteException e) { Slog.w(TAG, "Remote exception", e); return ActivityManager.BROADCAST_SUCCESS; } final boolean isCallerSystem; switch (UserHandle.getAppId(callingUid)) { case Process.ROOT_UID: case Process.SYSTEM_UID: case Process.SHELL_UID://AnsonCode make shell send system broadcast case Process.PHONE_UID: case Process.BLUETOOTH_UID: case Process.NFC_UID: isCallerSystem = true; break; default: isCallerSystem = (callerApp != null) && callerApp.persistent; break; } // First line security check before anything else: stop non-system apps from // sending protected broadcasts. if (!isCallerSystem) { if (isProtectedBroadcast) {//限制受保护广播, 并且抛出异常给APP. String msg = "Permission Denial: not allowed to send broadcast " + action + " from pid=" + callingPid + ", uid=" + callingUid; Slog.w(TAG, msg); throw new SecurityException(msg); } else if (AppWidgetManager.ACTION_APPWIDGET_CONFIGURE.equals(action) || AppWidgetManager.ACTION_APPWIDGET_UPDATE.equals(action)) { // Special case for compatibility: we don't want apps to send this, // but historically it has not been protected and apps may be using it // to poke their own app widget. So, instead of making it protected, // just limit it to the caller. if (callerPackage == null) { String msg = "Permission Denial: not allowed to send broadcast " + action + " from unknown caller."; Slog.w(TAG, msg); throw new SecurityException(msg); } else if (intent.getComponent() != null) { // They are good enough to send to an explicit component... verify // it is being sent to the calling app. if (!intent.getComponent().getPackageName().equals( callerPackage)) { String msg = "Permission Denial: not allowed to send broadcast " + action + " to " + intent.getComponent().getPackageName() + " from " + callerPackage; Slog.w(TAG, msg); throw new SecurityException(msg); } } else { // Limit broadcast to their own package. intent.setPackage(callerPackage); } } } ...使SHELL可以发送系统广播:|-- frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java @@ -18251,6 +18251,7 @@ public final class ActivityManagerService extends ActivityManagerNative switch (UserHandle.getAppId(callingUid)) { case Process.ROOT_UID: case Process.SYSTEM_UID: + case Process.SHELL_UID://make shell send system broadcast case Process.PHONE_UID: case Process.BLUETOOTH_UID: case Process.NFC_UID:添加广播以支持系统应用发送:|-- frameworks/base/core/res/AndroidManifest.xml @@ -143,6 +143,7 @@ <protected-broadcast android:name="android.bluetooth.device.action.SDP_RECORD" /> <protected-broadcast android:name="android.bluetooth.devicepicker.action.LAUNCH" /> <protected-broadcast android:name="android.bluetooth.devicepicker.action.DEVICE_SELECTED" /> + <protected-broadcast android:name="android.intent.action.NEW_BROADCAST"/>
平台rk3288 + android 7.12现象在7.1上, 进入分屏有两种方法,点击recent 键, 然后长按应用标题栏, 再拖放到分屏区长按recent键, 系统分自动进入分屏, 并让用户选择第二个需要显示的应用.在进入分屏时, UC浏览器提示: 应用可能无法在分屏模式下正常运行, 点击屏幕或等几秒钟后会自动消失并非所有应用都会提示.分析若想让应用不提示很简单, 给定支持分屏的属性即可:android:resizeableActivity="true" android:supportsPictureInPicture="true"这里不详细说明这两个属性.查查提示的字符串从何而来:|-- frameworks/base/packages/SystemUI/res/values-zh-rCN/strings.xml<string name="dock_forced_resizable" msgid="5914261505436217520">"应用可能无法在分屏模式下正常运行。"</string>|-- frameworks/base/packages/SystemUI/src/com/android/systemui/stackdivider/ForcedResizableInfoActivity.java//自动隐藏时间. private static final long DISMISS_DELAY = 2500; private final Runnable mFinishRunnable = new Runnable() { @Override public void run() { finish(); } }; @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.forced_resizable_activity); TextView tv = (TextView) findViewById(com.android.internal.R.id.message); tv.setText(R.string.dock_forced_resizable);//引用文本 getWindow().setTitle(getString(R.string.dock_forced_resizable)); getWindow().getDecorView().setOnTouchListener(this); } @Override protected void onStart() { super.onStart(); getWindow().getDecorView().postDelayed(mFinishRunnable, DISMISS_DELAY); }|-- frameworks/base/packages/SystemUI/src/com/android/systemui/stackdivider/ForcedResizableInfoActivityController.javapublic ForcedResizableInfoActivityController(Context context) { mContext = context; EventBus.getDefault().register(this); //注册TASK 监听, 并由 AM中回调 SystemServicesProxy.getInstance(context).registerTaskStackListener( new TaskStackListener() { @Override public void onActivityForcedResizable(String packageName, int taskId) { activityForcedResizable(packageName, taskId); } @Override public void onActivityDismissingDockedStack() { activityDismissingDockedStack(); } }); } private void activityForcedResizable(String packageName, int taskId) { if (debounce(packageName)) { return; } mPendingTaskIds.add(taskId); postTimeout(); } private void showPending() { mHandler.removeCallbacks(mTimeoutRunnable); for (int i = mPendingTaskIds.size() - 1; i >= 0; i--) { Intent intent = new Intent(mContext, ForcedResizableInfoActivity.class); ActivityOptions options = ActivityOptions.makeBasic(); options.setLaunchTaskId(mPendingTaskIds.valueAt(i));//设置Activity所属的TASK options.setTaskOverlay(true); mContext.startActivityAsUser(intent, options.toBundle(), UserHandle.CURRENT);//启动并显示提示 } mPendingTaskIds.clear(); }|-- frameworks/base/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java/** * Registers a task stack listener with the system. * This should be called on the main thread. */ public void registerTaskStackListener(TaskStackListener listener) { if (mIam == null) return; mTaskStackListeners.add(listener); if (mTaskStackListeners.size() == 1) { // Register mTaskStackListener to IActivityManager only once if needed. try { mIam.registerTaskStackListener(mTaskStackListener); } catch (Exception e) { Log.w(TAG, "Failed to call registerTaskStackListener", e); } } }AM 中调用onActivityForcedResizable()|-- frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java//收到消息并回调 case NOTIFY_FORCED_RESIZABLE_MSG: { synchronized (ActivityManagerService.this) { for (int i = mTaskStackListeners.beginBroadcast() - 1; i >= 0; i--) { try { // Make a one-way callback to the listener mTaskStackListeners.getBroadcastItem(i).onActivityForcedResizable( (String) msg.obj, msg.arg1); } catch (RemoteException e){ // Handled by the RemoteCallbackList } } mTaskStackListeners.finishBroadcast(); } break; }|-- frameworks/base/services/core/java/com/android/server/am/ActivityStackSupervisor.javavoid handleNonResizableTaskIfNeeded( TaskRecord task, int preferredStackId, int actualStackId, boolean forceNonResizable) { if ((!isStackDockedInEffect(actualStackId) && preferredStackId != DOCKED_STACK_ID) || task.isHomeTask()) { return; } final ActivityRecord topActivity = task.getTopActivity(); if (!task.canGoInDockedStack() || forceNonResizable) { // Display a warning toast that we tried to put a non-dockable task in the docked stack. mService.mHandler.sendEmptyMessage(NOTIFY_ACTIVITY_DISMISSING_DOCKED_STACK_MSG); // Dismiss docked stack. If task appeared to be in docked stack but is not resizable - // we need to move it to top of fullscreen stack, otherwise it will be covered. moveTasksToFullscreenStackLocked(DOCKED_STACK_ID, actualStackId == DOCKED_STACK_ID); } else if (topActivity != null && topActivity.isNonResizableOrForced() && !topActivity.noDisplay) {//判断是否需要发送NOTIFY_FORCED_RESIZABLE_MSG String packageName = topActivity.appInfo.packageName; mService.mHandler.obtainMessage(NOTIFY_FORCED_RESIZABLE_MSG, task.taskId, 0, packageName).sendToTarget(); } }关键函数判断是否发送FORCED_RESIZABLE 消息, 如果ActivityInfo 的 resizeMode是支持分屏的就不发送,反之则发送提示消息去启动显示信息:|-- frameworks/base/services/core/java/com/android/server/am/ActivityRecord.javaboolean isNonResizableOrForced() { return !isHomeActivity() && info.resizeMode != RESIZE_MODE_RESIZEABLE && info.resizeMode != RESIZE_MODE_RESIZEABLE_AND_PIPABLE; }两个常量分别对应分屏的模式:import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE; import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE_AND_PIPABLE;ActivityInfo 的由来:|-- frameworks/base/core/java/android/content/pm/ActivityInfo.java public int resizeMode = RESIZE_MODE_RESIZEABLE;|-- frameworks/base/services/core/java/com/android/server/am/ActivityRecord.javastatic ActivityRecord restoreFromXml(XmlPullParser in, ActivityStackSupervisor stackSupervisor) throws IOException, XmlPullParserException { ... final ActivityManagerService service = stackSupervisor.mService; final ActivityInfo aInfo = stackSupervisor.resolveActivity(intent, resolvedType, 0, null, userId); return r; }|-- frameworks/base/services/core/java/com/android/server/am/ActivityStarter.javafinal int startActivityLocked(IApplicationThread caller, Intent intent, Intent ephemeralIntent, String resolvedType, ActivityInfo aInfo, ResolveInfo rInfo, IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor, IBinder resultTo, String resultWho, int requestCode, int callingPid, int callingUid, String callingPackage, int realCallingPid, int realCallingUid, int startFlags, ActivityOptions options, boolean ignoreTargetSecurity, boolean componentSpecified, ActivityRecord[] outActivity, ActivityStackSupervisor.ActivityContainer container, TaskRecord inTask) { ... aInfo = mSupervisor.resolveActivity(intent, rInfo, startFlags, null /*profilerInfo*/); ... aInfo = mSupervisor.resolveActivity(intent, rInfo, startFlags, null /*profilerInfo*/); }调用的顺序一般是: 通过 PackageManagerService 获取ResolveInfo 再获取 ResolveInfo.ai|-- frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java@Override public ResolveInfo resolveIntent(Intent intent, String resolvedType, int flags, int userId) {..} private ResolveInfo chooseBestActivity(Intent intent, String resolvedType, int flags, List<ResolveInfo> query, int userId){}AndroidManifest.xml的解析工作是由PackageParser完成的, 这个类完成了Package, Service, Activity等组件的解析工作:|-- frameworks/base/core/java/android/content/pm/PackageParser.javaprivate Activity parseActivity(Package owner, Resources res, XmlResourceParser parser, int flags, String[] outError, boolean receiver, boolean hardwareAccelerated) throws XmlPullParserException, IOException { ... a.info.resizeMode = RESIZE_MODE_UNRESIZEABLE; final boolean appDefault = (owner.applicationInfo.privateFlags & PRIVATE_FLAG_RESIZEABLE_ACTIVITIES) != 0; // This flag is used to workaround the issue with ignored resizeableActivity param when // either targetSdkVersion is not set at all or <uses-sdk> tag is below <application> // tag in AndroidManifest. If this param was explicitly set to 'false' we need to set // corresponding resizeMode regardless of targetSdkVersion value at this point in time. final boolean resizeableSetExplicitly = sa.hasValue(R.styleable.AndroidManifestActivity_resizeableActivity); final boolean resizeable = sa.getBoolean( R.styleable.AndroidManifestActivity_resizeableActivity, appDefault); if (resizeable) { if (sa.getBoolean(R.styleable.AndroidManifestActivity_supportsPictureInPicture, false)) { a.info.resizeMode = RESIZE_MODE_RESIZEABLE_AND_PIPABLE; } else { a.info.resizeMode = RESIZE_MODE_RESIZEABLE; } } else if (owner.applicationInfo.targetSdkVersion >= Build.VERSION_CODES.N || resizeableSetExplicitly) { a.info.resizeMode = RESIZE_MODE_UNRESIZEABLE; } else if (!a.info.isFixedOrientation() && (a.info.flags & FLAG_IMMERSIVE) == 0) { a.info.resizeMode = RESIZE_MODE_FORCE_RESIZEABLE; } ... }
平台RK3288 + Android 5.1问题1. 系统初始版本为1.0.0, 包含了默认输入法 LatinIME(拉丁输入法) 和 OpenWnn(日文输入法) 2. OTA升级中, 内置讯飞输入法, 同时删除1.0.0版本中的两个输入法. 3. OTA升级后, 文本输入框无法正常调起输入法软键盘执行输入. 4. 打开设置 > 语言和输入法 > 键盘和输入法中, 当前输入法为空, 输入法中也没有看到 讯飞输入法分析Logcat 分析:01-02 03:14:58.469 system_process W/InputMethodManagerService: Couldn't create dir.: /data/system/inputmethod 01-02 03:14:58.479 system_process W/InputMethodManagerService: Default IME is uninstalled. Choose new default IME. 01-02 03:14:58.480 system_process W/InputMethodManagerService: Unknown input method from prefs: com.android.inputmethod.latin/.LatinIME java.lang.IllegalArgumentException: Unknown id: com.android.inputmethod.latin/.LatinIME at com.android.server.InputMethodManagerService.setInputMethodLocked(InputMethodManagerService.java:1806) at com.android.server.InputMethodManagerService.updateInputMethodsFromSettingsLocked(InputMethodManagerService.java:1756) at com.android.server.InputMethodManagerService.updateFromSettingsLocked(InputMethodManagerService.java:1715) at com.android.server.InputMethodManagerService.<init>(InputMethodManagerService.java:744) at com.android.server.SystemServer.startOtherServices(SystemServer.java:553) at com.android.server.SystemServer.run(SystemServer.java:261) at com.android.server.SystemServer.main(SystemServer.java:175) at java.lang.reflect.Method.invoke(Native Method) at java.lang.reflect.Method.invoke(Method.java:372) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:963) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:758)相关代码如下:|--frameworks/base/services/core/java/com/android/server/InputMethodManagerService.java void updateInputMethodsFromSettingsLocked(boolean enabledMayChange) { if (enabledMayChange) { List<InputMethodInfo> enabled = mSettings.getEnabledInputMethodListLocked(); for (int i=0; i<enabled.size(); i++) { // We allow the user to select "disabled until used" apps, so if they // are enabling one of those here we now need to make it enabled. InputMethodInfo imm = enabled.get(i); try { ApplicationInfo ai = mIPackageManager.getApplicationInfo(imm.getPackageName(), PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS, mSettings.getCurrentUserId()); if (ai != null && ai.enabledSetting == PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED) { if (DEBUG) { Slog.d(TAG, "Update state(" + imm.getId() + "): DISABLED_UNTIL_USED -> DEFAULT"); } mIPackageManager.setApplicationEnabledSetting(imm.getPackageName(), PackageManager.COMPONENT_ENABLED_STATE_DEFAULT, PackageManager.DONT_KILL_APP, mSettings.getCurrentUserId(), mContext.getBasePackageName()); } } catch (RemoteException e) { } } } // We are assuming that whoever is changing DEFAULT_INPUT_METHOD and // ENABLED_INPUT_METHODS is taking care of keeping them correctly in // sync, so we will never have a DEFAULT_INPUT_METHOD that is not // ena