浅谈Android4.4和Android L中的trim技术
来源:互联网 发布:电脑时间校对软件 编辑:程序博客网 时间:2024/05/17 01:55
一条ATA指令,由操作系统发送给SSD主控制器,告诉它哪些数据占有的地址是“无效的”。 其实就是操作系统将一部分的控制权交给了SSD主控制器,让操作系统与SSD主控制器有一个互动。因为闪存需要先擦除才能再次写入数据,要得到空闲的闪存空间,SSD必须复制所有“有效”页到新的“空白页”里,并且擦除旧块,即垃圾回收;避免了在操作系统要重新写入数据时, SSD才会知道哪些地址是无效的情况。这样就可以在适当的时机做最好的优化。 简而言之,这是一种能够让闪存长期工作后,也能维持高速度的技术。不少人长期使用安卓机后表示,安卓怎么就越用越卡,无论怎么刷系统清数据也没法回到刚买时的流畅度。这往往是由于长期使用后,闪存的垃圾回收效率大大降低,使得安卓机的I/O性能大跌造成的。安卓4.3支持Trim技术,能够大幅提升闪存垃圾回收效率,让闪存始终保持接近原始状态的高速度。 这样做既提高了“硬盘速度”, 同时也延长了SSD的使用寿命,垃圾回收!!!
2、调用trim整理NAND上碎片的两种方法
eg:fstab.qcom中有如下定义,
/dev/block/bootdevice/by-name/system /system ext4 ro,barrier=1,discard wait
其中的discard选项表示使用trim整理功能。
2、使用fstrim命令,当设备各传感器满足一定条件下就会从MountService.java中调用语句 — — > mConnector.execute("fstrim", "dotrim")启动trim整理功能,该语句将直接调用到vold层执行fstrim 命令。
3、fstrim命令实现流程简单介绍
3.1 Java Framework层
Framework层启动fstrim整理磁盘anroid L 和android4.4版本有所不同,将分别介绍两种方案。
3.1.1 android 4.4
可以分为两种方式,一是系统自我检测触发功能,二是手动输入命令直接触发功能。手动触发功能是USB连上手机后输入adb shell am idle-maintenance直接启动,frame
works/base/cmds/am/src/com/android/commands/am/Am.java中将注册com.android.server.IdleMaintenanceService.action.FORCE_IDLE_MAINTENANCE广播,在IdleMain
tenanceService.java下onReceive(...)将监听到广播,从而实现手动触发。下面重点介绍系统自我检测触发功能的相关流程,主流程如下:
1)SystemService.java中启动注册IdleMaintenaceServi
try { Slog.i(TAG, "IdleMaintenanceService"); new IdleMaintenanceService(context, battery); } catch (Throwable e) { reportWtf("starting IdleMaintenanceService", e); }
2)IdleMaintenanceService.java中注册各种广播和触发条件,register(Handler handler)中注册各种广播,如电量变化,屏幕开关等。在onReceive中监听广播,当收到Intent.ACTION_BATTERY_CHANGED,Intent.ACTION_SCREEN_ON,Intent.ACTION_DREAMING_STOPPED等广播时调用updateIdleMaintenanceState函数判断是否满足trim整理条件,android4.4在系统满足如下条件的情况,通过FSTRIM ioctl的方式对device进行垃圾回收的处理,条件如下:
*设备已经闲置了至少一小时
*在过去24小时内没有进行清理回收工作
*电池电量大于 30%(充电中)或者80%(未进行充电)
代码如下:
private void updateIdleMaintenanceState(boolean noisy) { ... if (mIdleMaintenanceStarted) { ... } else if (deviceStatePermitsIdleMaintenanceStart(noisy) && lastUserActivityPermitsIdleMaintenanceStart(noisy) && lastRunPermitsIdleMaintenanceStart(noisy)) {//这里调用三个函数分别判断三个条件 // Now that we started idle maintenance, we should schedule another // update for the moment when the idle maintenance times out. scheduleUpdateIdleMaintenanceState(MAX_IDLE_MAINTENANCE_DURATION); mIdleMaintenanceStarted = true; EventLogTags.writeIdleMaintenanceWindowStart(SystemClock.elapsedRealtime(), mLastUserActivityElapsedTimeMillis, mBatteryService.getBatteryLevel(), isBatteryCharging() ? 1 : 0); mLastIdleMaintenanceStartTimeMillis = SystemClock.elapsedRealtime(); sendIdleMaintenanceStartIntent();//条件满足,发送广播给MountService.java } }
3)在MountService.java广播中判断是否接收到广播
private final BroadcastReceiver mIdleMaintenanceReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { waitForReady(); String action = intent.getAction(); // Since fstrim will be run on a daily basis we do not expect // fstrim to be too long, so it is not interruptible. We will // implement interruption only in case we see issues. if (Intent.ACTION_IDLE_MAINTENANCE_START.equals(action)) { try { // This method runs on the handler thread, // so it is safe to directly call into vold. mConnector.execute("fstrim", "dotrim");//接收到广播,发送trim命令 EventLogTags.writeFstrimStart(SystemClock.elapsedRealtime()); } catch (NativeDaemonConnectorException ndce) { Slog.e(TAG, "Failed to run fstrim!"); } } } }4)通过NativeDameConnector.java中的Socket发送fstrim命令到vold层
public NativeDaemonEvent execute(String cmd, Object... args) throws NativeDaemonConnectorException { final NativeDaemonEvent[] events = executeForList(cmd, args);//异步发送fstrim指令,“mOutputStream.write(rawCmd.getBytes(StandardCharsets.UTF_8))” if (events.length != 1) { throw new NativeDaemonConnectorException( "Expected exactly one response, but received " + events.length); } return events[0]; }
3.1.2 android L
SystemServer.java -----> PackageManagerService.java ----> MountService.java ----> NativeDaemonConnector.java
1)SystemServer.java run()调用startOtherServices(),startOtherServices()调用PackageManagerService.java中的mPackageManagerService.performBootDexOpt()方法。
2)PackageManagerService.java performBootDexOpt()中判断是否满足trim整理的条件(在过去的三天没有进行垃圾回收工作),若满足则调用MountService中的runMaintenance()方法
public void performBootDexOpt() { ... // Before everything else, see whether we need to fstrim. try { IMountService ms = PackageHelper.getMountService(); if (ms != null) { final boolean isUpgrade = isUpgrade(); boolean doTrim = isUpgrade; if (doTrim) { Slog.w(TAG, "Running disk maintenance immediately due to system update"); } else { final long interval = android.provider.Settings.Global.getLong( mContext.getContentResolver(), android.provider.Settings.Global.FSTRIM_MANDATORY_INTERVAL, DEFAULT_MANDATORY_FSTRIM_INTERVAL); if (interval > 0) { final long timeSinceLast = System.currentTimeMillis() - ms.lastMaintenance(); if (timeSinceLast > interval) { doTrim = true; Slog.w(TAG, "No disk maintenance in " + timeSinceLast + "; running immediately"); } } } if (doTrim) { if (!isFirstBoot()) { ... } ms.runMaintenance(); ---- > MountService } } else { Slog.e(TAG, "Mount service unavailable!"); } } catch (RemoteException e) { // Can't happen; MountService is local } } }
3)MountService,通过mHandler.sendMessage(mHandler.obtainMessage(H_FSTRIM, callback))发送消息,并在Handler中处理H_FSTRIM
public void handleMessage(Message msg) { switch (msg.what) { ... case H_FSTRIM: waitForReady(); Slog.i(TAG, "Running fstrim idle maintenance"); // Remember when we kicked it off try { mLastMaintenance = System.currentTimeMillis(); mLastMaintenanceFile.setLastModified(mLastMaintenance); } catch (Exception e) { Slog.e(TAG, "Unable to record last fstrim!"); } try { // This method must be run on the main (handler) thread, // so it is safe to directly call into vold. mConnector.execute("fstrim", "dotrim");//发送trim命令 EventLogTags.writeFstrimStart(SystemClock.elapsedRealtime()); } catch (NativeDaemonConnectorException ndce) { Slog.e(TAG, "Failed to run fstrim!"); } ... break; } }
另外在MountService中也可以触发trim功能,通过mBootIPOReceiver和MountServiceHandler:case H_SYSTEM_READY里的handleSystemReady()触发该功能,handleSystemReady()中的MountServiceIdler.scheduleIdlePass(mContext)可触发,再看MountServiceIdle的代码,
public static void scheduleIdlePass(Context context) { JobScheduler tm = (JobScheduler) context.getSystemService(Context.JOB_SCHEDULER_SERVICE); Calendar calendar = tomorrowMidnight();//calendar.set(Calendar.HOUR_OF_DAY, 3)每天的三点 ... tm.schedule(builder.build());//执行JobScheduler }
MountServiceIdle继承JobService,调用MountServiceIdle时会执行MountServiceIdle中的onStartJob()方法,在onStartJob()方法中通过ms.runIdleMaintenance(mFinishCallback) 触发trim功能。其实就是每次开机或者每天的3点空闲时间也将触发trim整理功能。
4)可参照android4.4,两者一样。
3.2 vold层
CommandListener.cpp ----> fstrim.c
1)CommandListener.cpp中int CommandListener::FstrimCmd::runCommand(SocketClient *cli, int argc, char **argv)函数中接收到fstrim命令后做处理
int CommandListener::FstrimCmd::runCommand(SocketClient *cli, int argc, char **argv) { ...... if (!strcmp(argv[1], "dotrim")) { if (argc != 2) { cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: fstrim dotrim", false); return 0; } dumpArgs(argc, argv, -1); rc = fstrim_filesystems(); //接收到fstrim命令后,调用fstrim.c中的fstrim_filesystems()函数执行垃圾回收处理 } else { dumpArgs(argc, argv, -1); cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown fstrim cmd", false); } }
2)fstrim.c中执行垃圾回收处理命令
static void *do_fstrim_filesystems(void *ignored) { int i; int fd; int ret = 0; struct fstrim_range range = { 0 }; struct stat sb; extern struct fstab *fstab; SLOGI("Starting fstrim work...\n"); /* Log the start time in the event log */ LOG_EVENT_LONG(LOG_FSTRIM_START, get_boot_time_ms()); for (i = 0; i < fstab->num_entries; i++) { ...... fd = open(fstab->recs[i].mount_point, O_RDONLY); if (fd < 0) { SLOGE("Cannot open %s for FITRIM\n", fstab->recs[i].mount_point); ret = -1; continue; } memset(&range, 0, sizeof(range)); range.len = ULLONG_MAX; // 指定fitrim的范围是整个emmc SLOGI("Invoking FITRIM ioctl on %s", fstab->recs[i].mount_point); if (ioctl(fd, FITRIM, &range)) { // 调用特定文件系统中的FITRIM ioctl,执行真正的垃圾回收处理。 ...... close(fd); } } }
- 浅谈Android4.4和Android L中的trim技术
- android 中的trim 函数
- Android中的TRIM优化
- Android 4.3 中的 TRIM 优化
- BOM 和 JavaScript 中的 trim
- BOM和javascript中的trim
- 浅谈新一代Android操作系统Android L
- SSD TRIM和相关技术详解
- gcc中的选项-L和-l
- gcc参数中的-I, -L和-l
- gcc参数中的-I, -L和-l
- Android---Android4.4源码下载和编译
- 浅谈 Android L 的 Tint(着色)
- 浅谈 Android L 的 Tint(着色)
- 浅谈 Android L 的 Tint(着色)
- 浅谈 Android 中的地图和定位
- 浅谈Android和java中的多线程下载
- 浅谈Android和java中的多线程下载
- 工作备忘-Xcode7禁用了明码的HTTP请求
- Android通过tcpdump抓包
- heat项目动态(2015.9.25)
- 开放数据库互连(Open Database Connectivity,ODBC) 与PDO 事务的四个特征 XSS
- Ajax提交form表单
- 浅谈Android4.4和Android L中的trim技术
- 《Effective JavaScript》- 1.3 当心隐式的强制转换
- 简单的传统的阻塞的httpclient
- Codeforces 546D Soldier and Number Game
- 排序
- oracle数据库触发器(trigger)用法总结
- 详细解密FineReport中的报表执行过程
- nasm : test bit
- mssql数据库表转为oracle ,mysql数据库的建表语句。