首页 文章 精选 留言 我的

精选列表

搜索[智能解析],共10000篇文章
优秀的个人博客,低调大师

Android N DisplayManager服务解析(二)

版权声明:转载请联系本人,感谢配合!本站地址:http://blog.csdn.net/nomasp https://blog.csdn.net/NoMasp/article/details/77430743 PowerManagerService:负责协调设备上电源管理功能的服务。 DisplayPowerController:控制屏幕显示相关的电源状态。处理距离传感器、光线传感器和屏幕关闭时的动画等。这个组件在其他电源管理服务中是独立的,也就是说它不会共享任何状态,而只是通过异步回调来通知其他电源管理模块某些状态已经改变。这个类在内部做的一切都是被序列化的,尽管它可能被来自外部的其他线程访问。 DisplayManagerService:它管理显示的整个生命周期,决定怎样基于当前的物理显示设备来配置逻辑显示,并且当状态改变时发生通知给系统和应用。为了发现和配置依附于系统的一系列物理显示设备,DMS依赖于一系列 DisplayAdapter 组件。根据设备的不同分为不同的显示适配器:一个显示适配器用于内置的本地显示器;one for simulated non-functional displays when the system is headless;one for simulated overlay displays used for development;一个用于WiFi显示。通过注册的 DisplayAdapter.Listener ,适配器来和 DMS 异步地交流显示设备的状态。这里有两个主要的原因。 首先它很好的封装了两个类的职责:显示适配器处理各个显示设备,显示管理服务处理全局状态。其次,它消除了异步的查找显示设备时导致的死锁。 DisplayPowerState:控制显示状态。当属性改变的时候,该组件以统一的顺序发生一个回调以应用这些改变。这个组件必须且只能被属于 DPC 的 Looper 线程来创建和访问。 在PMS的systemReady方法中,会初始化各种组件,其中就包括这里的DMI,也就是DisplayManagerInternal,它位于hardware包下,作为显示管理的本地服务借口,而DMS等处于server包下,LocalService就继承于它,而DMS本身继承于SystemService。这SS是运行在系统进程中的用于server的基础类,负责提供了相关的生命周期和回调。 回调到DisplayManagerService LocalService.initPowerManagement DMS.requestGlobalDisplayStateInternal -> applyGlobalDisplayStateLocked -> updateDisplayStateLocked LocalDisplayDevice.requestDisplayStateLocked 以下都是在requestDisplayStateLocked返回的Runnable中调用的: SurfaceControl.setDisplayPowerMode 调到native层 mBacklight.setBrightness DisplayPowerController DPC控制屏幕显示相关的电源状态,包括距离传感器和光线传感器等。 这个类比较多庞大,我们逐步来看,首先是构造方法。在这里对它所持有的对象进行了初始化,包括以下内容: mHandler,内部持有的DisplayControllerHandler,用于分发事件。 mCallbacks, mBatteryStates, mSensorManager mWindowManagerPolicy mBlanker 调节屏幕电源状态,这里指的是屏幕状态,之后会通过mHandler来发送一条异步的MSG_UPDATE_POWER_STATE消息。 /** * Requests a new power state. * The controller makes a copy of the provided object and then * begins adjusting the power state to match what was requested. * * @param request The requested power state. * @param waitForNegativeProximity If true, issues a request to wait for * negative proximity before turning the screen back on, assuming the screen * was turned off by the proximity sensor. * @return True if display is ready, false if there are important changes that must * be made asynchronously (such as turning the screen on), in which case the caller * should grab a wake lock, watch for {@link DisplayPowerCallbacks#onStateChanged()} * then try the request again later until the state converges. */ public boolean requestPowerState(DisplayPowerRequest request, boolean waitForNegativeProximity) { if (DEBUG) { Slog.d(TAG, "requestPowerState: " + request + ", waitForNegativeProximity=" + waitForNegativeProximity); } synchronized (mLock) { boolean changed = false; if (waitForNegativeProximity && !mPendingWaitForNegativeProximityLocked) { mPendingWaitForNegativeProximityLocked = true; changed = true; } if (mPendingRequestLocked == null) { mPendingRequestLocked = new DisplayPowerRequest(request); changed = true; } else if (!mPendingRequestLocked.equals(request)) { mPendingRequestLocked.copyFrom(request); changed = true; } if (changed) { mDisplayReadyLocked = false; } if (changed && !mPendingRequestChangedLocked) { mPendingRequestChangedLocked = true; sendUpdatePowerStateLocked(); } return mDisplayReadyLocked; } } 接下来就看看对于MSG_UPDATE_POWER_STATE消息是如何处理的,在handler中直接调用了updatePowerState()方法。 initialize() 为默认显示设备初始化电源状态,包括根据屏幕状态和亮度反馈给电源Line 508 根据mPowerRequest.policy来设置state和brightness 对距离传感器做相应的操作 执行屏幕状态变化的动画 息屏时亮度设为BRIGHTNESS_OFF 判断和使用自动亮度 boost这个没有理解,再看看源码, 再分别对自动亮度和手动亮度调节做处理 如果低电量模式开启,在亮度的阀值之上,对亮度进行减半 在屏幕点亮状态或休眠时,animate屏幕亮度。如果是息屏、挂起,或者从VR状态转入转出时,跳过动画。 判断对于新的状态请求,显示设备是否就绪 通知policy屏幕已经点亮,真正执行时在mWindowManagerPolicy.screenTurnedOn() 获取锁、通知状态、释放锁 DisplayPowerState 该组件用于控制显示状态,当属性改变的时候,其以统一的顺序将这些改变回调出去。这个组件只能被DisplayPowerController的Looper线程来创建和访问。 DisplayPowerState主要负责设置屏幕状态和屏幕亮度等。这里的dozing也是一种屏幕状态,它是指在低电量模式下,屏幕的休眠状态,但是此时仍然是亮屏的,这是为了让屏幕在没有发生交互时而显示内容的一种优化(其中又分为DOZE和DOZE_SUSPEND两种状态,后者能够实现always-on等功能)。 /** * Sets whether the screen is on, off, or dozing. */ public void setScreenState(int state) { if (mScreenState != state) { if (DEBUG) { Slog.d(TAG, "setScreenState: state=" + state); } mScreenState = state; mScreenReady = false; scheduleScreenUpdate(); } } /** * Sets the display brightness. * * @param brightness The brightness, ranges from 0 (minimum / off) to 255 (brightest). */ public void setScreenBrightness(int brightness) { if (mScreenBrightness != brightness) { if (DEBUG) { Slog.d(TAG, "setScreenBrightness: brightness=" + brightness); } mScreenBrightness = brightness; if (mScreenState != Display.STATE_OFF) { mScreenReady = false; scheduleScreenUpdate(); } } } 其中最重要的就是这个scheduleScreenUpdate方法,它会去在mPhotonicModulator中异步地设置屏幕状态和亮度。 private final Runnable mScreenUpdateRunnable = new Runnable() { @Override public void run() { mScreenUpdatePending = false; int brightness = mScreenState != Display.STATE_OFF && mColorFadeLevel > 0f ? mScreenBrightness : 0; if (mPhotonicModulator.setState(mScreenState, brightness)) { if (DEBUG) { Slog.d(TAG, "Screen ready"); } mScreenReady = true; invokeCleanListenerIfNeeded(); } else { if (DEBUG) { Slog.d(TAG, "Screen not ready"); } } } }; 这个PhotonicModulator线程在DPS的构造函数中就已经start了,始终在运行着。那么对于一次setState操作,这个现场里究竟会发生什么呢? 1.在setState之后,该方法就会获取到mLock,这样在run中只会走到for循环里,但不会进到synchronized里面的代码中。 2.在setState中,首先会判断屏幕状态和背光是否发生改变,如果是就继续往下走,将这两个值赋给现场内部的mPending*,这个会在run()中使用。 3.判断状态是否都在改变中,判断完后分别进行赋值,如果不在就调用mLock.notifyAll()通知现场可以进行修改了。然后setState方法返回false,因为还没有设置完毕。 4.此时就轮到run方法中获取mLock了,在这里首先state和backlight会获取到来自setState中存储到线程内的值,如果设置的状态和实际的状态不一样,就不会将InProgress的值设为false,因为现在正是要进行修改。 5.然后就会去调用mBlander去设置屏幕状态和背光。 6.在屏幕状态和背光都设置好之后,因为是run方法,for循环还得继续,此时因为值没有变化,不用修改,所以就会去wait。 public boolean setState(int state, int backlight) { synchronized (mLock) { boolean stateChanged = state != mPendingState; boolean backlightChanged = backlight != mPendingBacklight; if (stateChanged || backlightChanged) { if (DEBUG) { Slog.d(TAG, "Requesting new screen state: state=" + Display.stateToString(state) + ", backlight=" + backlight); } mPendingState = state; mPendingBacklight = backlight; boolean changeInProgress = mStateChangeInProgress || mBacklightChangeInProgress; mStateChangeInProgress = stateChanged; mBacklightChangeInProgress = backlightChanged; if (!changeInProgress) { mLock.notifyAll(); } } return !mStateChangeInProgress; } } @Override public void run() { for (;;) { // Get pending change. final int state; final boolean stateChanged; final int backlight; final boolean backlightChanged; synchronized (mLock) { state = mPendingState; stateChanged = (state != mActualState); backlight = mPendingBacklight; backlightChanged = (backlight != mActualBacklight); if (!stateChanged) { // State changed applied, notify outer class. postScreenUpdateThreadSafe(); mStateChangeInProgress = false; } if (!backlightChanged) { mBacklightChangeInProgress = false; } if (!stateChanged && !backlightChanged) { try { mLock.wait(); } catch (InterruptedException ex) { } continue; } mActualState = state; mActualBacklight = backlight; } // Apply pending change. if (DEBUG) { Slog.d(TAG, "Updating screen state: state=" + Display.stateToString(state) + ", backlight=" + backlight); } mBlanker.requestDisplayState(state, backlight); } }

优秀的个人博客,低调大师

解析VMware存储协议之iSCSI

我们最近对VMware存储协议做了大量研究和测试,最后我总结出来在最重要的三个因素中——光纤通道(FC)、iSCSI和NAS(NFS)——iSCSI是最特别的。 首先,我觉得讨论协议和讨论重复数据删除一样很保险,但是让我来说一说我的看法。如果现在让你决定,摆在你面前的选择无非就是:8Gb光纤通道(也许是4Gb)、1GbiSCSI或者是采用了NFS的10Gb以太网。 如果是创建一个VMware存储架构的话,你会基于以下几个因素作出决定:性能、成本和易用性。当然,还有其他像安全性和可靠性的一些问题。但是大多数用户更关心前者。另外还有规格大小的问题——你最有可能选择你目前使用的规格或者你同事使用的规格。 如果纯粹谈性能的话,大多数人得承认光纤从很多方面来说都具有性能优势,而且如果你的主机和相关工作负载真的可以利用这个性能优势的话,那么你最有可能选择光纤。对许多用户来说,iSCSI和NFS的性能水平是可以接受的,尤其是刚开始的时候。 如果你可以轻松地通过iSCSI或者NFS维持I/O性能、而且两种协议在存储I/O性能方面也旗鼓相当,那么你将对比两者的易用性和成本。在很多人看来,iSCSI曾经是一项具有易用性的关键技术。人们普遍认为iSCSI是通过IP运行的,所以它的易用性肯定更高一些。我从2002年开始接触iSCSI技术,非常清楚这一点,尤其是当用户摆脱使用软件发起端(Software Initiator),而且他们可以接受标准以太网卡的性能。 而当你需要扩展iSCSI的时候iSCSI就开始给你带来难题。例如,在一个ESX环境下,你可能希望通过添加一个iSCSI HBA来进行扩展以卸载IP开销或者从SAN启动ESX Server.当开始调节性能的时候,你可能系统添加多个HBA、安装VLAN或者采取其他调节措施。这些都是可能的,但是很快你就会在进行架构规划的时候遇到难题,希望远离光纤通道架构来避免架构规划。 与此同时,光纤通道领域已经开始着眼于加强技术的易用性。虽然易用性会基于你的背景有所不同,许多人——包括我自己在内——发现光纤就像iSCSI一样即装即用,尤其是当你进行协议扩展的时候。你还会认为,使用iSCSI达到性能极限肯定会比光纤早。 不管哪种协议,你都要遇到基于块的访问问题,也就是VMFS或者RDM.这不是一个大问题,主要取决于你的背景,但却难倒了不少人。过去,唯一的选择就是块存储,所以无论是不是难题,或者没有选择余地,那么你就不得不解决它。NFS改变了这种情况,它能够处理对VMware存储的文件访问路径。 者:佚名 来源:51CTO

优秀的个人博客,低调大师

解析VMware存储协议之NFS

VMware 3.x提供了一项可以利用加载NFS的文件系统来托管VMware虚拟机镜像文件功能——VMDK。在缓慢开始发展之后,NFS获得了VMware存储越来越多的青睐。然而你必须了解现在普遍存在一些误导概念。 首先,这并不是关于光纤通道与IP协议的争论,而是关于NFS与VMFS。实际上,这甚至不能算是NFS与VMFS的争论,NFS只是一个传输协议。因此归根结底地说应该是VMFS与所选NAS的文件系统之间的争论。每个NAS制造商——EMC、NetApp或者Onstor——都有他们自己的文件系统,而且这些文件系统的价值应该与VMFS进行对比。也就是说,由于NAS的共享特点,这些厂商提供的功能都是大同小异的。 VMFS是VMware在块系统中提供用来托管虚拟机镜像的文件系统,这个系统在SAN中是可共享、可形成集群的。但是正如文件系统一样,它有自身的局限性,而NFS可以很好地解决这些局限性。NAS和使用NFS的NAS从本质上说都是基于共享的设备。VMDK实际上是一些文件,所以说,针对文件进行设计以满足任务要求的想法并不是本质上的飞跃。 在NFS中VMware最大的亮点就是日常运作,它是到目前为位置最容易配合运行的环境。使用NFS加载服务来创建分配VMware Datastore或者配置VMotion非常简单。重新配置这些资源库的大小——更大或者更小——就像虚拟机一样简单,而且不需要中断服务。相比之下,在使用VMFS的时候,大多数VMware管理者在进行数据存储或者扩展VMDK的时候都必须停止虚拟机运行,以保证其安全性。不管你采取了多少预防措施,缩减数据存储大小可能会导致很严重的问题,因此通常不建议用户这么做。 事实上,NFS是一种基于IP的协议,不过不是基于IP的存储协议,因此大大简化了操作并且降低了成本。然而你不能忽略规划环节。如果发生性能问题,那么扩展一个IP架构的复杂性就远远超过了光纤通道的复杂性。 使用IP遇到性能瓶颈要早于使用光纤通道,因为很多基础架构仍然是基于1Gb以太网的。10Gb以太网能够解决大多数性能瓶颈问题,但是由于队列问题,VMware主机中一个标准的10Gb以太网NIC只能提供现有带宽的40%~50%。为了解决这个难题,VMware开发出NetQueue,当它与英特尔、Neterion或者Solarflare等厂商提供的支持卡结合起来的时候,几乎能够完全实现线速度。所有这些会导致成本和复杂性的增加,再一次削弱了它的一些优势。 NFS/NAS和VMware的结合还存在其他一些挑战。你不能通过使用这种方法来启动ESX服务器,只能启动虚拟机,所以如果你希望从共享系统中启动所有应用的话,你还需要其他协议。其次,它不支持RDM,因此也就不支持Microsoft Clusters。如果这对你很重要的话,你同样需要使用其他协议。最后,从目前来看,NFS似乎是最后一个支持像VMotion和Site Recovery Manager这样VMware新功能的协议。 我们看到,NAS/NFS是低I/O需求工作负载的理想介质,光纤则是针对高需求工作负载的理想选择。 51CTO编者注:本文作者George Crump是Storage Switzerland网站创始人,该网站为存储用户、供应商和集成商提供战略咨询和分析。此前,他曾担任过美国最大集成商的首席技术官。 作者:George Crump 来源:51CTO

优秀的个人博客,低调大师

Android启动过程深入解析

当按下Android设备电源键时究竟发生了什么? Android的启动过程是怎么样的? 什么是Linux内核? 桌面系统linux内核与Android系统linux内核有什么区别? 什么是引导装载程序? 什么是Zygote? 什么是X86以及ARM linux? 什么是init.rc? 什么是系统服务? 当我们想到Android启动过程时,脑海中总是冒出很多疑问。本文将介绍Android的启动过程,希望能帮助你找到上面这些问题的答案。 Android是一个基于Linux的开源操作系统。x86(x86是一系列的基于intel 8086 CPU的计算机微处理器指令集架构)是linux内核部署最常见的系统。然而,所有的Android设备都是运行在ARM处理器(ARM 源自进阶精简指令集机器,源自ARM架构)上,除了英特尔的Xolo设备(http://xolo.in/xolo-x900-features)。Xolo来源自凌动1.6GHz x86处理器。Android设备或者嵌入设备或者基于linux的ARM设备的启动过程与桌面版本相比稍微有些差别。这篇文章中,我将解释Android设备的启动过程。深入linux启动过程是一篇讲桌面linux启动过程的好文。 当你按下电源开关后Android设备执行了以下步骤。 Android启动流程/过程 第一步:启动电源以及系统启动 当电源按下,引导芯片代码开始从预定义的地方(固化在ROM)开始执行。加载引导程序到RAM,然后执行。 第二步:引导程序 引导程序是在Android操作系统开始运行前的一个小程序。引导程序是运行的第一个程序,因此它是针对特定的主板与芯片的。设备制造商要么使用很受欢迎的引导程序比如redboot、uboot、qi bootloader或者开发自己的引导程序,它不是Android操作系统的一部分。引导程序是OEM厂商或者运营商加锁和限制的地方。 引导程序分两个阶段执行。第一个阶段,检测外部的RAM以及加载对第二阶段有用的程序;第二阶段,引导程序设置网络、内存等等。这些对于运行内核是必要的,为了达到特殊的目标,引导程序可以根据配置参数或者输入数据设置内核。 Android引导程序可以在\bootable\bootloader\legacy\usbloader找到。 传统的加载器包含的个文件,需要在这里说明: init.s初始化堆栈,清零BBS段,调用main.c的_main()函数; main.c初始化硬件(闹钟、主板、键盘、控制台),创建linux标签。 更多关于Android引导程序的可以在这里了解。 第三步:内核 Android内核与桌面linux内核启动的方式差不多。内核启动时,设置缓存、被保护存储器、计划列表,加载驱动。当内核完成系统设置,它首先在系统文件中寻找”init”文件,然后启动root进程或者系统的第一个进程。 第四步:init进程 init是第一个进程,我们可以说它是root进程或者说有进程的父进程。init进程有两个责任,一是挂载目录,比如/sys、/dev、/proc,二是运行init.rc脚本。 init进程可以在/system/core/init找到。 init.rc文件可以在/system/core/rootdir/init.rc找到。 readme.txt可以在/system/core/init/readme.txt找到。 对于init.rc文件,Android中有特定的格式以及规则。在Android中,我们叫做Android初始化语言。 Android初始化语言由四大类型的声明组成,即Actions(动作)、Commands(命令)、Services(服务)、以及Options(选项)。 Action(动作):动作是以命令流程命名的,有一个触发器决定动作是否发生。 语法 on <trigger> <command> <command> <command> Service(服务):服务是init进程启动的程序、当服务退出时init进程会视情况重启服务。 语法 service <name> <pathname> [<argument>]* <option> <option> ... Options(选项) 选项是对服务的描述。它们影响init进程如何以及何时启动服务。 咱们来看看默认的init.rc文件。这里我只列出了主要的事件以及服务。 Table Action/Service 描述 on early-init 设置init进程以及它创建的子进程的优先级,设置init进程的安全环境 on init 设置全局环境,为cpu accounting创建cgroup(资源控制)挂载点 on fs 挂载mtd分区 on post-fs 改变系统目录的访问权限 on post-fs-data 改变/data目录以及它的子目录的访问权限 on boot 基本网络的初始化,内存管理等等 service servicemanager 启动系统管理器管理所有的本地服务,比如位置、音频、Shared preference等等… service zygote 启动zygote作为应用进程 在这个阶段你可以在设备的屏幕上看到“Android”logo了。 第五步 在Java中,我们知道不同的虚拟机实例会为不同的应用分配不同的内存。假如Android应用应该尽可能快地启动,但如果Android系统为每一个应用启动不同的Dalvik虚拟机实例,就会消耗大量的内存以及时间。因此,为了克服这个问题,Android系统创造了”Zygote”。Zygote让Dalvik虚拟机共享代码、低内存占用以及最小的启动时间成为可能。Zygote是一个虚拟器进程,正如我们在前一个步骤所说的在系统引导的时候启动。Zygote预加载以及初始化核心库类。通常,这些核心类一般是只读的,也是Android SDK或者核心框架的一部分。在Java虚拟机中,每一个实例都有它自己的核心库类文件和堆对象的拷贝。 Zygote加载进程 加载ZygoteInit类,源代码:/frameworks/base/core/java/com/android/internal/os/ZygoteInit.java registerZygoteSocket()为zygote命令连接注册一个服务器套接字。 preloadClassed “preloaded-classes”是一个简单的包含一系列需要预加载类的文本文件,你可以在<Android Source>/frameworks/base找到“preloaded-classes”文件。 preloadResources() preloadResources也意味着本地主题、布局以及android.R文件中包含的所有东西都会用这个方法加载。 在这个阶段,你可以看到启动动画。 第六步:系统服务或服务 完成了上面几步之后,运行环境请求Zygote运行系统服务。系统服务同时使用native以及java编写,系统服务可以认为是一个进程。同一个系统服务在Android SDK可以以System Services形式获得。系统服务包含了所有的System Services。 Zygote创建新的进程去启动系统服务。你可以在ZygoteInit类的”startSystemServer”方法中找到源代码。 核心服务: 1.启动电源管理器; 2.创建Activity管理器; 3.启动电话注册; 4.启动包管理器; 5.设置Activity管理服务为系统进程; 6.启动上下文管理器; 7.启动系统Context Providers; 8.启动电池服务; 9.启动定时管理器; 10.启动传感服务; 11.启动窗口管理器; 12.启动蓝牙服务; 13.启动挂载服务。 其他服务: 1.启动状态栏服务; 2.启动硬件服务; 3.启动网络状态服务; 4.启动网络连接服务; 5.启动通知管理器; 6.启动设备存储监视服务; 7.启动定位管理器; 8.启动搜索服务; 9.启动剪切板服务; 10.启动登记服务; 11.启动壁纸服务; 12.启动音频服务; 13启动耳机监听; 14.启动AdbSettingsObserver(处理adb命令)。 第七步:引导完成 一旦系统服务在内存中跑起来了,Android就完成了引导过程。在这个时候“ACTION_BOOT_COMPLETED”开机启动广播就会发出去。 最新内容请见作者的GitHub页:http://qaseven.github.io/

优秀的个人博客,低调大师

Linux DNS解析异常的排查

1、系统可以正常ssh登陆 2、系统内ping域名提示unknown host 3、系统内ping ip可以通,内外网网关没问题 4、尝试重启/关闭nscd,测试问题还是没有得到解决。 5、抓包没有对外请求ping域名的时候抓包,发现没有对外53端口的请求,下图是ping的时候抓包的其他请求 6、使用strace ping -c 2 www.xxxxx.com 7、怀疑是selinux问题,检查没有配置 8、使用nslookup测试发现正常 根据帮助文档ping走的是nss,nslookup不走nss9、检查nsswitch.conf 对比正常的机器测试没有发现异常 10、nss没问题,看看hosts,发现有ipv6的痕迹 11、ipv6处理掉还是不行,继续排查,回滚原始的错误,重点先看resolv.conf 12、文件有问题,删掉resolvco

资源下载

更多资源
Nacos

Nacos

Nacos /nɑ:kəʊs/ 是 Dynamic Naming and Configuration Service 的首字母简称,一个易于构建 AI Agent 应用的动态服务发现、配置管理和AI智能体管理平台。Nacos 致力于帮助您发现、配置和管理微服务及AI智能体应用。Nacos 提供了一组简单易用的特性集,帮助您快速实现动态服务发现、服务配置、服务元数据、流量管理。Nacos 帮助您更敏捷和容易地构建、交付和管理微服务平台。

Spring

Spring

Spring框架(Spring Framework)是由Rod Johnson于2002年提出的开源Java企业级应用框架,旨在通过使用JavaBean替代传统EJB实现方式降低企业级编程开发的复杂性。该框架基于简单性、可测试性和松耦合性设计理念,提供核心容器、应用上下文、数据访问集成等模块,支持整合Hibernate、Struts等第三方框架,其适用范围不仅限于服务器端开发,绝大多数Java应用均可从中受益。

Rocky Linux

Rocky Linux

Rocky Linux(中文名:洛基)是由Gregory Kurtzer于2020年12月发起的企业级Linux发行版,作为CentOS稳定版停止维护后与RHEL(Red Hat Enterprise Linux)完全兼容的开源替代方案,由社区拥有并管理,支持x86_64、aarch64等架构。其通过重新编译RHEL源代码提供长期稳定性,采用模块化包装和SELinux安全架构,默认包含GNOME桌面环境及XFS文件系统,支持十年生命周期更新。

WebStorm

WebStorm

WebStorm 是jetbrains公司旗下一款JavaScript 开发工具。目前已经被广大中国JS开发者誉为“Web前端开发神器”、“最强大的HTML5编辑器”、“最智能的JavaScript IDE”等。与IntelliJ IDEA同源,继承了IntelliJ IDEA强大的JS部分的功能。

用户登录
用户注册