duangsuse::Echo
715 subscribers
4.25K photos
127 videos
583 files
6.46K links
import this:
美而不丑、明而不暗、短而不凡、长而不乱,扁平不宽,读而后码,行之天下,勿托地上天国。
异常勿吞,难过勿过,叹一真理。效率是很重要,盲目最是低效。
简明是可靠的先验,不是可靠的祭品。
知其变,守其恒,为天下式;穷其变,知不穷,得地上势。知变守恒却穷变知新,我认真理,我不认真。

技术相干订阅~
另外有 throws 闲杂频道 @dsuset
转载频道 @dsusep
极小可能会有批评zf的消息 如有不适可退出
suse小站(面向运气编程): https://WOJS.org/#/
Download Telegram
duangsuse::Echo
index 的实现使用了 Kotlin 扩展的 FileTreeWalker
其实说简单一点,还可以这么定义:

fun scanImageFiles(fromDir: File) {
val (added, ignored) = fromDir.walk().partition(Helper::isImageFile)

picturePathes.addAll(added.map(File::getAbsolutePath))

logger.warn("${added.size} images added, ${ignored.size} plain files ignored")
}
啊真是傻逼死了,我作为一个编译原理爱好者居然在这种已经完成了的事情上多花了这么多时间!难道这些时间不应该拿来写解释器...

最近刚想到 Dynamic Scoping 和 Lexical Scoping 怎么写
duangsuse::Echo
我待会把坑填完... #Android #blogPOst https://blog.yuuta.moe/2017/07/29/begin-dir/ 欸,Yuuta 的 Dir 在 17 年就开始了? 还是元旦? 原来 Yuuta 在我开发第一个应用之前就有作品? 🤔 WTF 我以为 Dir 是 18 年出的...
既然提到了 Yuuta 鱼塔大佬,那我就给你们快速了解一下鱼塔的博客

https://blog.yuuta.moe

我所认为所有有干货(技术上的信息)的博文,如下:

== JavaEE
https://blog.yuuta.moe/2017/05/30/webservlet-jetty-appserver/
这篇博文《WebServlet+Jetty+Nginx轻松开发并部署应用服务器》是讲 Java Servlet 架构后端服务器 + Jetty 应用服务器 + Maven 开发 Http 服务端应用的

文章使用了 IntelliJ IDEA Community 作为演示 IDE、Maven 作为自动构建和依赖管理系统(J2EE 最令人头疼的事情来了:XML,一大堆名字... 还必须得填,如果忘了还得想,哪些属性还没设置呢...)

应用程序的 classpath 是由 maven Jetty 插件管理的,使用了 lifecycle:jetty:run
应用程序的调试是 IDEA 远程调试,这个讲了一些

servlet 的东西就不用说了,想必都能默写出来,后面会有精简手册。

Abstract:
我最近需要为 Dir 开发后端应用服务器,以前是用的某SaaS服务平台(也是WebServlet),觉得太贵,于是需要部署到自己的服务器。目前有比较成熟的 Python 、PHP 和 JavaScript等语言 可用,但是我需要尽快开发出来,不能花时间新学一门语言,于是就选择了一直在用的 WebServlet。

== Android
https://blog.yuuta.moe/2017/05/05/use-app_process/

使用 app_process (Android DalvikVM 的前端,Zygote client)
举了个 Kill.java (用 Android Privileged Activities API 杀 CoolMarket)栗子
教了大家不使用 IDE 的 Android/Java 命令行工具开发

https://blog.yuuta.moe/2017/09/12/new-way-access-hidden-api/

Android SDK 有些不允许使用的内部 API(Hidden API)
这些 API 没有在官方 android.jar 接口包里定义,并且,现在还不允许直接使用 Java 反射使用这些接口(虚拟机上做了检查,black-grey List)
(谈到 Android.jar,也顺带了解一下 Gradle 的 implementationcompile 有啥区别吧)(你的应用依赖的库,他们不管依赖什么都不会影响到你的应用,反观 compile 则会让你的项目传递性依赖他们所依赖的东西)

就是说使用替换 Android.jar 的方式啦。

至于可不可能,因为运行时 Android 设备上是有这些类/方法的,不会找不到(但也有可能没有,所以如果这么 Hack,不能被 javac 的无报错迷惑,为了程序健壮性写好 catch finally 块)。
但是,因为我不知道到底是什么情况,到底具体捕捉那种 Exception 不清楚,自己查字节码(比如,invokevirtual

说到这里,继续科普一下 JVM 1.7 时候的一些 invoke* 指令:

(后面跟的都是用途之一而已)
invokestatic:调用静态方法
invokespecial:调用构造器
invokeinterface:寻找调用某接口抽象方法的实现
invokevirtual:调用虚方法(很多时候『非静态』方法都是虚的,Kotlin 里面很多方法都不是虚方法 — 只有 open 的方法可以被复写以支持子类型多态)

JVM 1.8 的时候加入了特别的 invokedynamic 允许用户代码协作 JVM 进行方法查找
这也实现了 Lambda(因为要使用 LambdaFactory 为指定接口创建实例对象),因为 DalvikVM 没有增添此方法,Android Dexer 使用 RuntimeDesugar 反射解决 Lambda 对象生成的问题。

顺便科普一下,Kotlin 和 Java 8 都支持『SingleAbstractMethod』单抽象方法 Lambda
也即:
abstract class Invokable<T> { @FunctionalInterface T invoke(); }
static <T> T doInvoke(Invokable f) { return f.invoke(); }
//...
Invokable fn = new Invokable<Void>(() -> System.out.println("Invokable invoked"));
doInvoke(fn); // Invokable invoked
但是不允许 Lambda 实现 SAM 接口,只能实现抽象类。

https://blog.yuuta.moe/2017/07/10/zygote-appprocess-init/

你们不要被 Trumeet 放在上面的那张图迷惑了,其实这篇文章的内容很简单,也不包含流程分析。

简单介绍了一下 Zygote 和 /sbin/init 的关系,app_process 是什么

贴了 zygote RunCommand service 的代码

https://blog.yuuta.moe/2018/12/10/optimize-docker-image-by-using-multi-stage-building/

这个我之前说过,看这里

https://blog.yuuta.moe/2017/11/10/from-vibrator-to-system-service/

待会会讲,谈到了 Android Service 的架构,并且实现了一个『需要特权』的 Service

大概是这样的:


[outsider] OOServer
^
| AIDL IPC / IBinder
OOService [协调 C/S] IOOServeice (Stub.asInterface)
^
|
OO

此外还有 OOManager 和 SeviceResgistry 这种东西,待会画图

https://blog.yuuta.moe/2017/07/10/appprocess-uid/
简单的知识点科普,不到半面可以速看:

app-process 与 内部运行的Java 程序的UID是如何决定的 呢..

+ 使用 Root 执行 app_process 可行,进程 UID 是 Root
+ 使用 ADB,则 UID 是 Shell
+ 使用普通应用,则 UID 是应用的 UID u*_a*

也就是说 app_pocess 内的Java程序是和启动者的UID一致,而不是只允许Shell/Root调用app_process(
普通应用启动,UID也是普通应用的,想获取一些系统权限照样是不行的,保障了安全(

详情可以自己找资料了解 UNIX 进程权限系统,这个很好记。
不过对 Java 应用来说,并没有一个所谓的『进程』来运行它,它的线程们独占整个虚拟机,而虚拟机就代表了『Java 程序』的操作系统视角
做系统调用的话,检查的也是 Calling VM process 的权限,很好理解的,和 Bash Shell 解释器 fork 子进程是一个道理



———
最后总结一下最值得一看的文章:

⭐️https://blog.yuuta.moe/2017/11/10/from-vibrator-to-system-service/
⭐️https://blog.yuuta.moe/2017/05/30/webservlet-jetty-appserver/
⭐️https://blog.yuuta.moe/2017/05/05/use-app_process/

是贴了不少代码的
方式选错了... #KDE
正确的打开方式:
Vibrator.svg
24 KB
Vibrator.png
255.5 KB
对应的位图 #Share #Android #svg
Vibrator.svg
27.8 KB
最后完整注释的版本 #Android
duangsuse::Echo
最后完整注释的版本 #Android
This media is not supported in your browser
VIEW IN TELEGRAM
睡觉睡觉,我可懒得老是管 XML 和几个接口/抽象类定义的事情...

CachedServiceFetcher、registerService、permission-group、checkSelfOrCallingPermission 什么的,你们自己看吧,给张图就跑~
This media is not supported in your browser
VIEW IN TELEGRAM
因为 Telegram 一直连不上,白白浪费了很多时间!
一个小时是有的
This media is not supported in your browser
VIEW IN TELEGRAM
效率.... 🤐

那既然已经花了很多时间就再多花一点(皮)

演示一下这个功能:

[DuangSUSE@duangsuse]
~/WallpapperSlide% cd ~/Projects/RandomPicture
~/Projects/RandomPicture% ./gradlew build

BUILD
SUCCESSFUL in 1s
12 actionable tasks: 9 executed, 3 up-to-date

~/Projects/RandomPicture% cp build/libs/server-1.0-SNAPSHOT.jar ~/bin; cd -

##
~/WallpapperSlide% java -jar ~/bin/server-1.0-SNAPSHOT.jar

四月
01, 2019 11:29:18 上午 org.duangsuse.fushion.RandomPicture
信息: Checking with regex /^.*\.(png|jpg|jpeg|gif|webp|raw|bmp|img|svg)$/
Server started at http://localhost:8080
信息: Registering refresh list signal handler...
信息: Finished registration
严重: Failed in deploying verticle
io.vertx.core.impl.NoStackTraceThrowable: Input path /app/favourite (RANDOM_PICTURE) should be exists and is folder
(其实我应该用 then 而不是 all 的,不过机不可失,逃跑)
##


RANDOM_PICTURE=. java -jar ~/bin/server-1.0-SNAPSHOT.jar

信息
: Begin indexing images
四月 01, 2019 11:29:31 上午 org.duangsuse.fushion.RandomPicture
信息: Begin >
四月 01, 2019 11:29:31 上午 org.duangsuse.fushion.RandomPicture
信息: Finished > (.) costs 1 ms
信息: Finished > (png) costs 0 ms
四月 01, 2019 11:29:31 上午 org.duangsuse.fushion.RandomPicture
警告: Ignoring non-picture file ./png

警告: 8 files ignored, 75 files added
信息: Finished indexing images size 75 costs 19 ms

Server started at http://localhost:8080

信息: Registering refresh list signal handler...
信息: Finished registration

<Ctrl-C(INT)
信息: Refreshing pictures list...

== All files
0: /home/DuangSUSE/WallpapperSlide/昨日青空/./后来谁又在这里装作不经意的看过谁.jpg
...
74: /home/DuangSUSE/WallpapperSlide/昨日青空/./l-2.jpg

信息: Begin Cleaning old list
信息: Finished Cleaning old list costs 1 ms

信息: Begin Indexing new images...
警告: 8 files ignored, 75 files added
信息: Finished Indexing new images... 0 files added costs 14 ms

<Ctrl+Z(HUP)
mv origin.jpg.bak origin.jpg
fg %RANDOM_PICTURE=.

警告
: 7 files ignored, 76 files added
信息: Finished Indexing new images... 1 files added costs 7 ms
== New files
/home/DuangSUSE/WallpapperSlide/昨日青空/./origin.jpg

<Ctrl+Z
kill -TERM %RANDOM_PICTURE=.

🤔 SIGQUIT 都被 HotSpot 占用了... 欸
如果是生产环境的话,可以用 USR1、USR2 代替这种操作,毕竟也不常用(可以用于不停服刷新静态数据)。

当然,Java 也提供了文件夹更新监听器,所以这种操作完全不用手工弄,也不用完全重新扫描整个文件树,直接用 fs watcher 监听就好 #backend #Kotlin #Java
其他操作,比如输出更新 log 什么的,可以试试 UNIX Signal
duangsuse::Echo
最后完整注释的版本 #Android
最后,快速了解一下 #Android 系统服务吧,看来这个星期又是啥都没干成... 🤐

== 简而言之

就是简单的『强类型』 C/S 架构喽

(下面的 Class#method% 方法表示我不想提及 method 的方法列表,但它是方法不是实例字段)
Service,就是 Android IPC 的 OOService

Service Server 使用 ServiceManager#addService% 和 ServiceManager#getService% 注册和获取 IBinder

abstract class ServiceConnection
onServiceConnected(ComponentName name, IBinder service)

但是注册 Service 对象的程序应该持续运行,一般使用 Looper 的 mainLooper
一般要进行权限认证,Context#checkCallingOrSelfPermission
没有 Context,使用 ActivityThread 拿到 system main thread,再拿 system Context。
检查相等性 PackageManager.PERMISSION_GRANTED

XML 符号:
tag permission-group { android:name android:icon android:label }
tag permission { android:name android:icon android:label android:permission-group android:protectionLevel }

Client,就是 OO,它找 ServiceManager 拿到一个 IBinder 对象,然后进行 IOOService.Stub.asService 转换,保证接口是清真无混乱的(IBinder 好比果的 HTTP 协议、AIDL 则是我们自己对协议的约束)

API,就是 IOOService,可以使用 AIDL 语言定义,用来利用 Android IPC 系统传递我们自己的消息

Manager,就是你自己提供一些辅助函数,比如 getOOService()

== 根据符号们:

—> 应用程序
class Vibrator
class android.os.SystemVibrator extends Vibrator
AIDL interface IVibratorService
abstact class IVibratorService.Stub

public class VibratorService extends IVibratorService.Stub implements InputManager.InputDeviceListener
public void VibratorService#vibrate(int uid, String opPkg, long milliseconds, int usageHint, IBinder token)


Context#getSystemService(@ServiceName String! serviceId)
Context.VIBRATOR_SERVICE

—> SystemServer
class com.android.server.SystemServer
traceBeginAndSlog(String)
ServiceManager.addService(String, IBinder)
traceEnd()

SystemServer#startOtherServices()
SystemServer#main()
SystemServer#run()

SystemServiceManager#startService()
ServiceManager#addService(String, IBinder)
ServiceManager#getService(String)

—> Services API
class android.app.SystemServiceRegistry
abstract class CachedServiceFetcher<T> { T createService(ContextImpl ctx); }
registerService(name, ServiceFetcher)

abstract class ServiceConnection
onServiceConnected(ComponentName name, IBinder service)

IXXXService.Stub.asInterface(service);


—> Android API
class android.os.Looper
Looper#prepareMainLooper();
Looper#loop%
activityThread.getSystemContext%
ActivityThread#systemMain
android.permission.SHUTDOWN
IPowerManager
IPowerManager#shutdown
Context.POWER_SERVICE
PowerManager.SHUTDOWN_USER_REQUESTED
Context#checkCallingOrSelfPermission



http://androidxref.com/8.0.0_r4/xref/frameworks/base/services/java/com/android/server/SystemServer.java#475