EnablePulseAudioInSystemMode

目的

在Ubuntu 18.04.6上配置pulseaudio的 system-wide daemon模式,以使得pulseaudio为所有用户可用。

步骤

确保pulseaudio被安装(默认应该是被安装的), 撰写一个systemd服务条目,重新定义其启动方式(做完以下步骤后需要重新启动机器), 需注意需要手动执行usermod一行为所有用户添加到组里:

# vi /etc/systemd/system/pulseaudio.service
[Unit]
Description=PulseAudio Daemon
 
[Install]
WantedBy=multi-user.target
 
[Service]
Type=simple
PrivateTmp=true
ExecStart=/usr/bin/pulseaudio --system --realtime --disallow-exit --no-cpu-limit 
# vi /usr/share/dbus-1/system.d/pulseaudio.conf 
<?xml version="1.0"?> <!--*-nxml-*-->
<!DOCTYPE busconfig PUBLIC "-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN"
 "http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
<busconfig>
    <policy group="pulse">
        <allow own="org.pulseaudio.Server"/>
    </policy>

    <policy context="default">
        <allow send_destination="org.pulseaudio.Server"/>
        <allow receive_sender="org.pulseaudio.Server"/>
    </policy>
</busconfig>
# groupadd --system pulse
# groupadd --system pulse-access
# useradd --system -g pulse -G audio -d /var/run/pulse -m pulse
# usermod -G video,pulse-access root
# usermod -G video,pulse-access test
# usermod -G video,pulse-access seat1
# usermod -G video,pulse-access seat2
# echo "default-server = /var/run/pulse/native" >> /etc/pulse/client.conf
# echo "autospawn = no" >> /etc/pulse/client.conf
# systemctl daemon-reload
# systemctl enable pulseaudio
# reboot

重启后,以ssh登陆到各用户下,在命令行下播放音频,如用mplayer 1.mp3等操作,应该可以看到音频被正确解码,但是此时无声音,应该使用以下命令unmute音道.

开启所有音道:

# pactl set-sink-mute @DEFAULT_SINK@ false

WorkingTipsOnSG1

Steps

Before installing device drivers:

[root@localhost test]# ls /dev/dri
ls: cannot access /dev/dri: No such file or directory

Changes to ubuntu(I think centos will fail)

ChangesInAOSP12Unfinished

aosp修改要点

TBD, 因为这里还没有完全理出来。

ChangeItemsInAOSP11

目的

这里记录开启转码支持所需要更改的文件列表

build/target/board/generic_x86_64/BoardConfig.mk, 在文件的尾部添加关于ABI架构支持的列表:

 # Native Bridge ABI List
 NB_ABI_LIST_32_BIT := armeabi-v7a armeabi
 NB_ABI_LIST_64_BIT := arm64-v8a
 
 TARGET_CPU_ABI_LIST_64_BIT ?= $(TARGET_CPU_ABI) $(TARGET_CPU_ABI2)
 TARGET_CPU_ABI_LIST_32_BIT ?= $(TARGET_2ND_CPU_ABI) $(TARGET_2ND_CPU_ABI2)
 TARGET_CPU_ABI_LIST := \
     $(TARGET_CPU_ABI_LIST_64_BIT) \
     $(TARGET_CPU_ABI_LIST_32_BIT) \
     $(NB_ABI_LIST_64_BIT) \
     $(NB_ABI_LIST_32_BIT)
 TARGET_CPU_ABI_LIST_32_BIT += $(NB_ABI_LIST_32_BIT)
 TARGET_CPU_ABI_LIST_64_BIT += $(NB_ABI_LIST_64_BIT)

build/target/board/generic_x86_64/device.mk, 文件结尾处添加关于nativebridge的编译(这里关于属性的配置似乎无法生效,所以后面会在libart.mk中配置属性):

# Added houdini
$(call inherit-product-if-exists, vendor/google/chromeos-x86/target/houdini.mk)
$(call inherit-product-if-exists, vendor/google/chromeos-x86/target/native_bridge_arm_on_x86.mk)
PRODUCT_SYSTEM_DEFAULT_PROPERTIES += persist.sys.nativebridge=1

# Get native bridge settings
$(call inherit-product-if-exists,device/generic/common/nativebridge/nativebridge.mk)


# NativeBridge
PRODUCT_PACKAGES += libhoudini houdini
PRODUCT_PROPERTY_OVERRIDES += ro.dalvik.vm.isa.arm=x86 ro.enable.native.bridge.exec=1
PRODUCT_DEFAULT_PROPERTY_OVERRIDES += ro.dalvik.vm.isa.arm=x86 ro.enable.native.bridge.exec=1

PRODUCT_PACKAGES += houdini64
PRODUCT_PROPERTY_OVERRIDES += ro.dalvik.vm.isa.arm64=x86_64 ro.enable.native.bridge.exec64=1
PRODUCT_DEFAULT_PROPERTY_OVERRIDES += ro.dalvik.vm.isa.arm64=x86_64 ro.enable.native.bridge.exec64=1

PRODUCT_DEFAULT_PROPERTY_OVERRIDES += ro.dalvik.vm.native.bridge=libhoudini.so

build/target/product/AndroidProducts.mk中加入关于编译时lunch的选项:

COMMON_LUNCH_CHOICES := \
.......
     sdk_phone_x86_64-userdebug \

build/target/product/runtime_libart.mk中注释掉ro.dalvik.vm.native.bridge=0的默认设置,加入关于ro.dalvik.vm.isa.arm及其他几个参数配置

#PRODUCT_SYSTEM_DEFAULT_PROPERTIES += \
#    ro.dalvik.vm.native.bridge=0

PRODUCT_SYSTEM_DEFAULT_PROPERTIES += \
     ro.dalvik.vm.isa.arm=x86 \
     ro.enable.native.bridge.exec=1 \
     ro.dalvik.vm.isa.arm64=x86_64 \
     ro.enable.native.bridge.exec64=1 \

build/target/product/sdk_phone_x86.mkbuild/target/product/sdk_phone_x86_64.mk中添加所需要拷贝的静态库的定义:

#PRODUCT_ARTIFACT_PATH_REQUIREMENT_ALLOWED_LIST
# PRODUCT_ARTIFACT_PATH_REQUIREMENT_WHITELIST := \
#

PRODUCT_ARTIFACT_PATH_REQUIREMENT_ALLOWED_LIST := \
     system/bin/houdini \
     system/bin/houdini64 \
     system/etc/binfmt_misc/arm64_dyn \
.......

device/generic/x86_64/BoardConfig.mk 中添加以下规则:

PRC_COMPATIBILITY_PACKAGE := true
BUILD_ARM_FOR_X86 := true
-include vendor/google/chromeos-x86/board/native_bridge_arm_on_x86.mk

device/generic/x86_64/mini_x86_64.mk中添加关于nativebridge的编译:

$(call inherit-product-if-exists,device/generic/common/nativebridge/nativebridge.mk)

frameworks/base/core/java/com/android/internal/content/NativeLibraryHelper.java区别:

7,88d86
<         final String pkgName;
<         final String apkDir;
99,110d96
<         public static String getApkDirFromCodePath(String codePath) {
<             if (codePath == null ||
<                 codePath.startsWith("/system/") ||
<                 codePath.startsWith("/system_ext/") ||
<                 codePath.startsWith("/product/") ||
<                 codePath.startsWith("/vendor/") ||
<                 codePath.startsWith("/oem/")) {
<                 return null;
<             }
<             return codePath;
<         }
< 
113c99
<                     lite.debuggable, lite.packageName, getApkDirFromCodePath(lite.codePath));
---
>                     lite.debuggable);
117c103
<                 boolean extractNativeLibs, boolean debuggable, String pkgName, String apkdir) throws IOException {
---
>                 boolean extractNativeLibs, boolean debuggable) throws IOException {
134c120
<             return new Handle(apkPaths, apkHandles, multiArch, extractNativeLibs, debuggable, pkgName, apkdir);
---
>             return new Handle(apkPaths, apkHandles, multiArch, extractNativeLibs, debuggable);
146c132
<                     lite.extractNativeLibs, lite.debuggable, lite.packageName, getApkDirFromCodePath(lite.codePath));
---
>                     lite.extractNativeLibs, lite.debuggable);
150c136
<                 boolean extractNativeLibs, boolean debuggable, String pkgName, String apkdir) {
---
>                 boolean extractNativeLibs, boolean debuggable) {
156,157d141
<             this.pkgName = pkgName;
<             this.apkDir = apkdir;
232,234c216
<             final int res = nativeFindSupportedAbiReplace(apkHandle, supportedAbis,
<                     handle.debuggable, handle.pkgName, handle.apkDir);
< 
---
>             final int res = nativeFindSupportedAbi(apkHandle, supportedAbis, handle.debuggable);
256,257c238,239
<     private native static int nativeFindSupportedAbiReplace(long handle, String[] supportedAbis,
<             boolean debuggable, String pkgName, String apkdir);
---
>     private native static int nativeFindSupportedAbi(long handle, String[] supportedAbis,
>             boolean debuggable);

frameworks/base/core/jni/Android.bp中添加编译规则:

15d14
<         "-D_PRC_COMPATIBILITY_PACKAGE_",
71d69
<                 "abipicker/ABIPicker.cpp",

frameworks/base/core/jni/com_android_internal_content_NativeLibraryHelper.cpp中添加:

42,45d41
< #ifdef _PRC_COMPATIBILITY_PACKAGE_
< #include "abipicker/ABIPicker.h"
< #endif
< 
60,64d55
< #ifdef _PRC_COMPATIBILITY_PACKAGE_
< #define X86ABI     "x86"
< #define X8664ABI   "x86_64"
< #endif
< 
517,524c508,509
< com_android_internal_content_NativeLibraryHelper_findSupportedAbi_replace(
<         JNIEnv *env,
<         jclass clazz,
<         jlong apkHandle,
<         jobjectArray javaCpuAbisToSearch,
<         jboolean debuggable,
<         jstring apkPkgName,
<         jstring apkDir)
---
> com_android_internal_content_NativeLibraryHelper_findSupportedAbi(JNIEnv *env, jclass clazz,
>         jlong apkHandle, jobjectArray javaCpuAbisToSearch, jboolean debuggable)
526,612c511
< #ifdef _PRC_COMPATIBILITY_PACKAGE_
< 
<     int abiType = findSupportedAbi(env, apkHandle, javaCpuAbisToSearch, debuggable);
<     if (apkDir == NULL) {
<         return (jint)abiType;
<     }
< 
<     char abiFlag[256] = {'\0'};
<     ScopedUtfChars apkdir(env, apkDir);
<     size_t apkdir_size = apkdir.size();
<     const int numAbis = env->GetArrayLength(javaCpuAbisToSearch);
<     Vector<ScopedUtfChars*> supportedAbis;
< 
<     assert(apkdir_size < 256 - 15);
<     if (strlcpy(abiFlag, apkdir.c_str(), 256) != apkdir.size()) {
<         return (jint)abiType;
<     }
< 
<     int abiIndex = 0;
<     abiFlag[apkdir_size] = '/';
<     abiFlag[apkdir_size + 1] = '.';
<     for (abiIndex = 0; abiIndex < numAbis; abiIndex++) {
<         ScopedUtfChars* abiName = new ScopedUtfChars(env,
<                  (jstring)env->GetObjectArrayElement(javaCpuAbisToSearch, abiIndex));
<         supportedAbis.push_back(abiName);
<         if (abiName == NULL || abiName->c_str() == NULL || abiName->size() <= 0) {
<             break;
<         }
<         if ((strlcpy(abiFlag + apkdir_size + 2, abiName->c_str(), 256 - apkdir_size - 2)
<                     == abiName->size()) && (access(abiFlag, F_OK) == 0)) {
<             abiType = abiIndex;
<             break;
<         }
<     }
< 
<     if (abiIndex < numAbis) {
<         for (int j = 0; j < abiIndex; ++j) {
<             if (supportedAbis[j] != NULL) {
<                 delete supportedAbis[j];
<             }
<         }
<         return (jint)abiType;
<     }
< 
<     do {
<         if (abiType < 0 || abiType >= numAbis) {
<             break;
<         }
< 
<         if (0 != strcmp(supportedAbis[abiType]->c_str(), X86ABI) &&
<                 0 != strcmp(supportedAbis[abiType]->c_str(), X8664ABI)) {
<             break;
<         }
< 
<         ScopedUtfChars name(env, apkPkgName);
<         if (NULL == name.c_str()) {
<             break;
<         }
< 
<         if (isInOEMWhiteList(name.c_str())) {
<             break;
<         }
< 
<         ABIPicker picker(name.c_str(),supportedAbis);
<         if (!picker.buildNativeLibList((void*)apkHandle)) {
<             break;
<         }
< 
<         abiType = picker.pickupRightABI(abiType);
<         if (abiType >= 0 && abiType < numAbis &&
<                 (strlcpy(abiFlag + apkdir_size + 2, supportedAbis[abiType]->c_str(),
<                          256 - apkdir_size - 2) == supportedAbis[abiType]->size())) {
<             int flagFp = creat(abiFlag, 0644);
<             if (flagFp != -1) {
<                 close(flagFp);
<             }
<         }
< 
<     } while(0);
< 
<     for (int i = 0; i < numAbis; ++i) {
<         delete supportedAbis[i];
<     }
<     return (jint)abiType;
< #else
<     return (jint)findSupportedAbi(env, apkHandle, javaCpuAbisToSearch, debuggable);
< #endif
---
>     return (jint) findSupportedAbi(env, apkHandle, javaCpuAbisToSearch, debuggable);
703,705c602,604
<     {"nativeFindSupportedAbiReplace",
<             "(J[Ljava/lang/String;ZLjava/lang/String;Ljava/lang/String;)I",
<             (void *)com_android_internal_content_NativeLibraryHelper_findSupportedAbi_replace},
---
>     {"nativeFindSupportedAbi",
>             "(J[Ljava/lang/String;Z)I",
>             (void *)com_android_internal_content_NativeLibraryHelper_findSupportedAbi},

frameworks/base/services/core/java/com/android/server/pm/parsing/pkg/AndroidPackageUtils.java添加:

139,141c139
<                 pkg.isDebuggable(),
<                 pkg.getPackageName(),
<                 NativeLibraryHelper.Handle.getApkDirFromCodePath(pkg.getCodePath())
---
>                 pkg.isDebuggable()

system/linkerconfig/contents/namespace/systemdefault.cc添加关于空间权限:

build/system/linkerconfig/contents/namespace/systemdefault.cc origin/system/linkerconfig/contents/namespace/systemdefault.cc
67,70d66
<         "/system/lib/arm",
<         "/system/lib/arm/nb",
<         "/system/lib64/arm64",
<         "/system/lib64/arm64/nb",

20220225 added:

需加入abipicker的支持:

scp -r ./frameworks/base/core/jni/abipicker/ remote_folder

上传/vendor目录下的相关内容:

scp -r vendor/google/ root@192.168.xx.xxx:/root/Code/redroid_11/vendor/

如果是redroid的编译,而对应需要修改redroid文件的定义:

# vim device/redroid/redroid_x86_64/device.mk
PRODUCT_PACKAGES += \
    vulkan.intel \

# Added houdini
$(call inherit-product-if-exists, vendor/google/chromeos-x86/target/houdini.mk)
$(call inherit-product-if-exists, vendor/google/chromeos-x86/target/native_bridge_arm_on_x86.mk)
PRODUCT_SYSTEM_DEFAULT_PROPERTIES += persist.sys.nativebridge=1

# Get native bridge settings
$(call inherit-product-if-exists,device/generic/common/nativebridge/nativebridge.mk)


# NativeBridge
PRODUCT_PACKAGES += libhoudini houdini
PRODUCT_PROPERTY_OVERRIDES += ro.dalvik.vm.isa.arm=x86 ro.enable.native.bridge.exec=1
PRODUCT_DEFAULT_PROPERTY_OVERRIDES += ro.dalvik.vm.isa.arm=x86 ro.enable.native.bridge.exec=1

PRODUCT_PACKAGES += houdini64
PRODUCT_PROPERTY_OVERRIDES += ro.dalvik.vm.isa.arm64=x86_64 ro.enable.native.bridge.exec64=1
PRODUCT_DEFAULT_PROPERTY_OVERRIDES += ro.dalvik.vm.isa.arm64=x86_64 ro.enable.native.bridge.exec64=1

PRODUCT_DEFAULT_PROPERTY_OVERRIDES += ro.dalvik.vm.native.bridge=libhoudini.so


# vim device/TARGET_CPU_ABI := x86_64
TARGET_ARCH := x86_64
TARGET_ARCH_VARIANT := x86_64

TARGET_2ND_CPU_ABI := x86
TARGET_2ND_ARCH := x86
TARGET_2ND_ARCH_VARIANT := x86_64

include build/make/target/board/BoardConfigGsiCommon.mk

TARGET_USERIMAGES_SPARSE_EXT_DISABLED := true

BOARD_VENDORIMAGE_FILE_SYSTEM_TYPE := ext4
BOARD_VENDORIMAGE_PARTITION_RESERVED_SIZE := 16777216
BOARD_SYSTEMIMAGE_PARTITION_RESERVED_SIZE := 16777216

BOARD_MESA3D_USES_MESON_BUILD := true
BOARD_MESA3D_GALLIUM_DRIVERS := virgl radeonsi i915 iris crocus
BOARD_MESA3D_VULKAN_DRIVERS := virtio-experimental amd intel

DEVICE_MANIFEST_FILE += device/redroid/manifest.xml
PRC_COMPATIBILITY_PACKAGE := true
BUILD_ARM_FOR_X86 := true
-include vendor/google/chromeos-x86/board/native_bridge_arm_on_x86.mk

# Native Bridge ABI List
NB_ABI_LIST_32_BIT := armeabi-v7a armeabi
NB_ABI_LIST_64_BIT := arm64-v8a

TARGET_CPU_ABI_LIST_64_BIT ?= $(TARGET_CPU_ABI) $(TARGET_CPU_ABI2)
TARGET_CPU_ABI_LIST_32_BIT ?= $(TARGET_2ND_CPU_ABI) $(TARGET_2ND_CPU_ABI2)
TARGET_CPU_ABI_LIST := \
    $(TARGET_CPU_ABI_LIST_64_BIT) \
    $(TARGET_CPU_ABI_LIST_32_BIT) \
    $(NB_ABI_LIST_64_BIT) \
    $(NB_ABI_LIST_32_BIT)
TARGET_CPU_ABI_LIST_32_BIT += $(NB_ABI_LIST_32_BIT)
TARGET_CPU_ABI_LIST_64_BIT += $(NB_ABI_LIST_64_BIT)

WorkingTipsOnMultiSeatUbuntu200403

前提

基准操作系统为ubuntu-20.04.3-live-server-amd64.iso, 不可以安装为desktop版本的iso。

系统及包更新

确保系统更新到最新:

$ sudo apt-get update -y && sudo apt-get upgrade -y

安装必要的包(这里需要严格按照顺序来安装,否则会出现多安装包的情况导致gdm被安装后sddm无法正常工作):

$ sudo apt-get install -y sddm unzip autoconf automake libtool pkg-config build-essential x11proto-dev xserver-xorg-dev libxcb-util-dev libxcb-icccm4-dev libxcb-image0-dev libxcb-shm0-dev libxcb-randr0-dev vim cmake cmake-extras extra-cmake-modules libpam-dev libxcb-xkb-dev qt5-default libqt5qml5 qt5-qmltooling-plugins qtdeclarative5-dev xutils-dev
$ sudo apt-get install openbox --no-install-recommends --no-install-suggests
$ sudo apt-get install -y xinit

Multi-seat编译/配置

multi-seat-2004.tar.gz上传到机器上,解压:

$ tar xzvf multi-seat-2004.tar.gz
$ ls
multi-seat sddm
$ cd multi-seat/
$ ls
sddm_config  sddm-nested-multiseat  udev_config  xf86-video-nested  xorg_config

注意在20.04的系统中,不需要编译sddm-nested-multiseat,因为编译的过程中会引入gdm3,后期我们用直接拷贝二进制文件的方式安装sddm-nested-multiseat

编译xf86-video-nested包:

$ cd xf86-video-nested
$ ./autogen.sh && ./configure --prefix=/usr && make -j2 && sudo make install

安装sddm-nested:

$ cd sddm
$ ./install.sh

更新sddm登陆免密配置文件:

$ cd sddm_config
$ sudo cp * /etc/pam.d

配置桌面登陆

更新xorg定义文件:

$ cd xorg_config
$ sudo mkdir -p /etc/X11/xorg.conf.d
$ sudo cp xorg.conf.d/20-intel.conf /etc/X11/xorg.conf.d
$ sudo cp seat* /etc/X11
$ sudo cp /bin/sed /usr/bin/sed

配置USB口与seat的映射关系(从已有的例子进行修改):

$ cd udev_config
$ vim 70-seat.rules
修改完毕后:   
$ sudo cp 70-seat.rules /etc/udev/rules.d/70-seat.rules

开启multi-seat:

$ sudo vim /etc/default/grub
.....
GRUB_CMDLINE_LINUX_DEFAULT="quiet splash startseat=true"
GRUB_CMDLINE_LINUX="startseat=true"
....
$ sudo update-grub2

建立两个用于登陆的用户:

$ sudo useradd -m seat1
$ sudo useradd -m seat2
$ sudo passwd seat1
$ sudo passwd seat2

配置sddm为两个用户的自动登陆([AutoLogin]内只保留如下所示部分):

# cat /etc/sddm.conf | more
[Autologin]
# Whether sddm should automatically log back into sessions when they exit
# Whether sddm should automatically log back into sessions when they exit
Relogin=false,false
SeatName=seat1,seat2
#Session=awesome,awesome
Session=xfce,xfce
User=seat1,seat2
....
此时重启后可以看到,双屏方案在登陆前自动进入到图形界面并已经实现分屏.