Android 报告 java.lang.StackOverflowErrors 异常的问题分析

一般情况下,在使用比较复杂的布局的时候,尤其是 Fragment + ViewPager + SlideMenu 这种组合的情况下,会报告类似如下内容的崩溃栈信息

at android.view.View.draw(View.java:6880)
at android.view.ViewGroup.drawChild(ViewGroup.java:1646)
at android.view.ViewGroup.dispatchDraw(ViewGroup.java:1373)
at android.view.View.draw(View.java:6883)
at android.view.ViewGroup.drawChild(ViewGroup.java:1646)
at android.view.ViewGroup.dispatchDraw(ViewGroup.java:1373)
...

该异常在 2.X版本的Android系统上面表现尤为明显,往往 4.X版本的一切正常或者偶有卡顿,在 2.X版本上面直接崩溃。

分析一下,是一个 draw() -> dispatchDraw() -> drawChild() 的深度递归调用导致栈的溢出越界。对于 Android目前使用的 dalvik 虚拟机而言,系统默认的栈深度如下

Browsing for stack sizes through the dalvik source history:

也就是说,如果 draw() -> dispatchDraw() -> drawChild()  递归的深度太深,就会导致栈的不足问题。

解决方法, 目前貌似 dalvik 虚拟机 并不支持动态的修改栈的深度,这导致问题复杂化,首先,Fragment + ViewPager + SlideMenu  这种组合,即是什么都不增加,就已经有超过 10 层的递归了,这个可以在崩溃栈中的 drawChild 函数的数量就可以统计出来,这也就意味着,目前只有一条路可以走,那就是想办法减少布局的层次。有建议废弃 Fragment 来自己实现一套完整的东西,暂时还不建议如此操作。

一般方法就是

1.使用RelativeLayout 来减少尤其是 LinearLayout导致的布局深度问题,尽量在同层展开。

2.复杂布局的情况下,可以使用自定义View来实现,实在不行,可以自己计算坐标,直接绘制,比如用类似游戏的SurfaceView 之类的东西来替代。

3.利用 merge 来简化收缩布局,目前貌似FrameLayout 上面比较合适。

4.继承ViewGroup 的自定义View也是一层,这点不要忘记,能直接继承View的,就不要继承 ViewGroup

其他的方法,根据实际项目来处理好了。

Android抽象布局——include、merge 、ViewStub

在布局优化中,Android的官方提到了这三种布局,并介绍了这三种布局各有的优势,下面也是简单说一下他们的优势,以及怎么使用,记下来权当做笔记。

1、布局重用
标签能够重用布局文件,简单的使用如下:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical" 
    android:layout_width=”match_parent”
    android:layout_height=”match_parent”
    android:background="@color/app_bg"
    android:gravity="center_horizontal">

    <include layout="@layout/titlebar"/>

    <TextView android:layout_width=”match_parent”
              android:layout_height="wrap_content"
              android:text="@string/hello"
              android:padding="10dp" />

    ...

</LinearLayout>

1)标签可以使用单独的layout属性,这个也是必须使用的。

2)可以使用其他属性。标签若指定了ID属性,而你的layout也定义了ID,则你的layout的ID会被覆盖。
3)在include标签中所有的android:layout_*都是有效的,前提是必须要写layout_width和layout_height两个属性。
4)布局中可以包含两个相同的include标签,引用时可以使用如下方法解决(参考):

View bookmarks_container_2 = findViewById(R.id.bookmarks_favourite);
bookmarks_container_2.findViewById(R.id.bookmarks_list);

2、减少视图层级

标签在UI的结构优化中起着非常重要的作用,它可以删减多余的层级,优化UI。多用于替换FrameLayout或者当一个布局包含另一个时,标签消除视图层次结构中多余的视图组。例如你的主布局文件是垂直布局,引入了一个垂直布局的include,这是如果include布局使用的LinearLayout就没意义了,使用的话反而减慢你的UI表现。这时可以使用标签优化。

<merge xmlns:android="http://schemas.android.com/apk/res/android">

    <Button
        android:layout_width="fill_parent" 
        android:layout_height="wrap_content"
        android:text="@string/add"/>

    <Button
        android:layout_width="fill_parent" 
        android:layout_height="wrap_content"
        android:text="@string/delete"/>

</merge>

现在,当你添加该布局文件时(使用标签),系统忽略节点并且直接添加两个Button。更多介绍可以参考《Android Layout Tricks #3: Optimize by merging

3、需要时使用
标签最大的优点是当你需要时才会加载,使用他并不会影响UI初始化时的性能。各种不常用的布局想进度条、显示错误消息等可以使用标签,以减少内存使用量,加快渲染速度。是一个不可见的,大小为0的View。标签使用如下:

<ViewStub
    android:id="@+id/stub_import"
    android:inflatedId="@+id/panel_import"
    android:layout="@layout/progress_overlay"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:layout_gravity="bottom" />

当你想加载布局时,可以使用下面其中一种方法:

((ViewStub) findViewById(R.id.stub_import)).setVisibility(View.VISIBLE);
// or
View importPanel = ((ViewStub) findViewById(R.id.stub_import)).inflate();

当调用inflate()函数的时候,ViewStub被引用的资源替代,并且返回引用的view。 这样程序可以直接得到引用的view而不用再次调用函数findViewById()来查找了。
注:ViewStub目前有个缺陷就是还不支持 标签。

更多标签介绍可以参考《Android Layout Tricks #3: Optimize with stubs

转自 http://blog.csdn.net/xyz_lmn/article/details/14524567

Android 背景图片平铺

一般布局设置的背景图都是做拉伸处理,有时候我们需要背景图片做平铺处理,类似于网页开发中CSS的repeat。
在Android中可以使用如下方法使背景图片平铺。在drawable目录下创建一个repeat_bg.xml:

<?xml version="1.0" encoding="utf-8"?>  
<bitmap xmlns:android="http://schemas.android.com/apk/res/android"   
    android:src="@drawable/bg"
    android:tileMode="repeat" />

然后在布局的xml文件中可以这样引用:

<LinearLayout 
    android:layout_width="fill_parent" 
    android:layout_height="fill_parent" 
    android:background="@drawable/repeat_bg"> 
</LinearLayout>

Mac SSD TRIM的终极方案

该方法在 Mac 10.9.1 版本上面有效。

Enable SSD TRIM for Mac, Ultimate Solution. TRIM终极方案 我的Mac机型是Mac mini Late 2012,把硬盘换成了SSD。试了多种打开SSD TRIM的教程,总不能成功,有一次还弄到系统无法启动。今天大盘开始盘整了,于是可以静下心来把那些教程仔细debug一遍,发现了问题所在,成功开启了SSD TRIM。

最重要的先讲:在做这个工作之前,用Time Machine备份机器。

其次是怎么会弄到系统无法启动?原因是在改写IOAHCIBlockStorage这个文件的时候,把权限破坏了。一旦权限不对,系统会显示警告窗口,说无法加载IOAHCIBlockStorage。千万不要忽视这个警告,去重启机器,而是应该先修复权限。最简单最彻底的办法就是使用Disk Utility,选择系统盘,然后Repare Disk Permissions.

为什么有些教程会不起作用呢?这是因为不同的系统版本,如10.8.1、10.8.2,加上不同的机型,特别是新机型,系统文件有可能是不一样的。
如果教程不起作用,那就要先理解这些开启SSD TRIM办法的实质:其实就是把IOAHCIBlockStorage文件中硬盘型号的字符“APPLE SSD”这九个字节抹去,替换成全零字节。但是在整个文件中做全替换也不行,只能替换含义为硬盘型号字符的字节。
就因为各种系统和机型的文件不同,同时又要选择性地做替换,于是出现了不同的教程。这里介绍的终极方案,就是先查看你机器上的IOAHCIBlockStorage文件,然后修改教程中的一条命令,然后再执行那些命令。

ugmbbc_001734902074378

用一个二进制编辑器(比如说“Hex Fiend”)打开

/System/Library/Extensions/IOAHCIFamily.kext/Contents/PlugIns/IOAHCIBlockStorage.kext/Contents/MacOS/IOAHCIBlockStorage

搜索十六进制“52 6F 74 61 74 69 6F 6E 61 6C 00”,也就是“Rotational”字串加上0结尾。整个文件我就只搜到一个匹配的。查看后面是不是9个字符的“APPLE SSD”,如果是的话,就看“APPLE SSD”接下来的字符是什么。图中是“Time To Ready”,记下这个字串的第一个字符,是“T”,他的十六进制是54。

接下来就修改那些教程中的命令,请看https://gist.github.com/3334193,点击“Download Gist”下载文件,然后双击打开,就会自动解压缩。修改文件enable_trim.sh中的(x00{1,20}x51)中的51为上文的54,修改完就是(x00{1,20}x54),保存文件。解压的这个enable_trim.sh文件是没有执行权限的,那就在控制台运行“chmod 755 enable_trim.sh”,赋予执行权限。

注意,对于由于某墙封锁导致的不能访问github 问题,可以直接复制如下代码来自己生成sh文件

#!/bin/bash
#
# Enable TRIM support for 3rd Party SSDs. Works for Mountain Lion
#
# Source: http://digitaldj.net/2011/07/21/trim-enabler-for-lion/

set -e
set -x

# Back up the file we're patching
sudo cp \
  /System/Library/Extensions/IOAHCIFamily.kext/Contents/PlugIns/IOAHCIBlockStorage.kext/Contents/MacOS/IOAHCIBlockStorage \
  /System/Library/Extensions/IOAHCIFamily.kext/Contents/PlugIns/IOAHCIBlockStorage.kext/Contents/MacOS/IOAHCIBlockStorage.original

# Patch the file to enable TRIM support
sudo perl -pi -e 's|(\x52\x6F\x74\x61\x74\x69\x6F\x6E\x61\x6C\x00{1,20})[^\x00]{9}(\x00{1,20}\x51)|$1\x00\x00\x00\x00\x00\x00\x00\x00\x00$2|sg' \
  /System/Library/Extensions/IOAHCIFamily.kext/Contents/PlugIns/IOAHCIBlockStorage.kext/Contents/MacOS/IOAHCIBlockStorage

# Force a reboot of the system's kernel extension cache
sudo touch /System/Library/Extensions/

echo "Now reboot!"

在运行“./enable_trim.sh”之前,一定要保证你现在的

/System/Library/Extensions/IOAHCIFamily.kext/Contents/PlugIns/IOAHCIBlockStorage.kext/Contents/MacOS/IOAHCIBlockStorage

文件一定是未经修改的原系统文件。执行完毕后,系统如果没有弹出什么提示框,那就万事大吉了。有兴趣的话,你还可以用Hex Fiend查看一下修改后的文件,和原文件相比,有啥不同。

ugmbbc_0016571229804857
手工重启机器后,应该就是成功了。
ugmbbc_0017201152901000

参考连接 http://www.cnbeta.com/articles/219752.htm

解决WD MyCloud 通过SSH 登陆之后中文显示问题

WD MyCloud通过SSH登陆之后中文显示为问号,网上查询了一下,找到解决方法。

首先执行

$ locale -a 
C
cs_CZ.utf8
C.UTF-8
de_DE.utf8
en_US.utf8
es_ES.utf8
fr_FR.utf8
hu_HU.utf8
it_IT.utf8
ja_JP.utf8
ko_KR.utf8
nb_NO.utf8
nl_NL.utf8
pl_PL.utf8
POSIX
pt_BR.utf8
ru_RU.utf8
sv_SE.utf8
tr_TR.utf8
zh_CN.utf8
zh_TW.utf8

可以看到,在输出中是存在中文的“zh_CN.utf8”,因此,只要启用就可以了。

因此,执行如下命令

$ sudo apt-get update

$ sudo apt-get install vim

$ cd ~

$ vim .bashrc

然后修改里面的

export LC_ALL=C

export LC_ALL='zh_CN.utf8'

然后,退出,重新登陆终端即可。

WD My Cloud NAS on Ubuntu

下文暂时没有办法处理有用户名,密码的情况。

I decided that 2014 for me was going to be the year of the Network Attached Storage (NAS). Last year was the year that I finally abandoned my desktops and went all laptop for both my Mac-based iOS development workflow and general purpose computing (i.e, everything else on my Acer i5 running Lubuntu). This year I wanted to have a massive centralized storage where I could put all my videos and photos so I can access it from any laptop or mobile device. What follows is what I chose and how to hook it up to Lubuntu.

I first looked at external cloud solutions (DropBox, Box, CrashPlan, BackBlaze) and although they were all cool they were unfortunately out for me due to three reasons. First, the storage limits – I didn’t want Gigs – I wanted Terabytes. Although, CrashPlan and BackBlaze both offer unlimited online storage they limit the number of devices. Two, I didn’t have all the files centralized on one computer and it would be best to centralized all my Mac, Linux, and iOS data first before I could go to one of these offsite back-up solutions. Third, these all cost money in a form of a monthly fee of $5 or $50 yearly subscriptions. These offline solutions are definitely part of the final solution but I decided that would be a second phase for me. It looked like I had developed a phased project that broke down into two phases of centralization first and then offsite continuous backup second.

The first phase then came down to having a Network Attached Storage (NAS) type unit. The new Airport Time Capsule looked cool but I wanted something less Appley. I have had good experiences with Western Digital (WD) drives and saw in the January 2014 issue of Maximum PC a head-to-head between Dropbox and the new WD My Cloud product. A successor to the My Book branded drive this new My Cloud branded offering provides a shell to a NAS device and it was cheaper than a Time Capsule. I was sold and for X-mas asked Santa for the WD My Cloud 4TB Personal Cloud Storage – NAS (WDBCTL0040HWT-NESN) device.

Set-up was literally plug and play. There is an iOS App for iPad and iPhone/iPod Touch which allows upload to and download/stream from the NAS. The WD website and User Manual mention Mac and PC software to mount and sync that make connection a breeze. The device supports Time Capsule so I’ll be doing that with my Mac laptops (yes – there is no limit to how many computers connect to this thing). Then came my Linux laptop. There was no mention of Linux which is a shame since you would think that they are leveraging the community’s efforts in their products. But it was easy enough to connect my Lubuntu laptop as a Network File System (NFS) Client via three shell commands.

First, I changed directory to my home directory and created a nfs directory in there:

$ cd $HOME

$ mkdir nfs

Then I applied the following three shell commands:

$ sudo apt-get install nfs-common

$ showmount -e <IP Address of Device>

$ sudo mount -o soft,intr,rsize=8192,wsize=8192 192.168.1.132:/nfs /home/<yourMachine>/nfs/

If you cd into nfs you’ll be accessing the WD My Cloud device. That’s it. I started to copy twenty mp4 files totalling 1.6GB into the device through 802.11g and it took 8 minutes. I was then streaming these on my iPad mini.

I hope this helps assure you you can connect to this from Linux. I know once I finished the plug and play I panicked for a bit thinking I wouldn’t be able to connect my Linux machines to this device but now I happily throw everything I have onto this. Also, it has a USB 3 port on the back so I can simply plug another 4TB USB drive on it and expand it in the future.

引用链接 http://cocoaallocinit.com/2014/01/04/wd-my-cloud-nas-on-ubuntu/

拯救死翘翘了的WD MyCloud

WD MyCloud 在通过SSH 进入命令行的时候误操作,导致系统彻底完蛋,查找了很长时间,找到了解决方法。

  • 对于彻底完蛋了的系统,比如,已经无法进入系统了,不管是SSH 还是网页,总之就是系统动不了。 则参考如下操作:(注意本方法会导致数据被彻底删除,使用时候要慎重

1.从http://pan.baidu.com/s/1eQBVbc2 下载3TB 版本的系统恢复镜像。

2.拆开机器,系统出厂自带的是Debian linux系统,重装系统需要将外壳拿掉,将硬盘取出。外壳是通过卡扣连接主体的,拆的时候有可能会折断卡扣,但不会影响重装回去之后的外观。大致方法就是,找几张废旧电话卡或银行卡从机子的后背也就是网卡口的左右两侧的外壳缝隙插进去,稍微撬开一点缝隙,保持卡片不动,然后将外壳用巧力使劲往 前推,慢慢的推出去,即可把外壳拆下。硬盘和壳子通过4个胶垫固定,先抬起硬盘一侧,使得两个胶垫脱离壳子,然后再慢慢向上和向外取出即可,过程没什么技 术含量,只需要小心一点就是了。连接主板和硬盘有4颗螺丝,其中一颗在led灯胶垫下,掰开胶垫可见,一并拧下。

3.把硬盘挂载到一台Linux的机器,推荐使用 Ubuntu ,本机使用的是 Ubuntu 13.10 .挂载的时候,可以使用USB 或者 ESATA接口的移动硬盘盒即可。

4.建议删除原始磁盘上的所有分区

root@y-System-Product-Name:/# parted
GNU Parted 2.3
Using /dev/sda
Welcome to GNU Parted! Type 'help' to view a list of commands.
(parted) select /dev/sdb 
Using /dev/sdb 
(parted) mklabel gpt
Warning: The existing disk label on /dev/sdb will be destroyed and all data on this disk will be lost. Do you
want to continue?
Yes/No? y 
(parted) quit 
Information: You may need to update /etc/fstab.

5.使用 如下命令强制还原镜像到硬盘,假定此时硬盘被挂载到了 /dev/sdb上

$ sudo dd if=/mnt/usb/MyCloud3TB.img of=/dev/sdb bs=1M

6.装回硬盘到 WD My Cloud ,(注意此时不要用Linux 自带的gparted 操作硬盘,否则会导致无法启动),然后开启 SSH ,在命令行中执行 parted 命令,此时,会提示分区存在问题,按照提示修复即可。尽量在My Cloud 里面执行脚本命令,外面的Linux 执行命令的话,经常导致无法启动问题,最好在My Cloud 里面执行一下 e2fsck 来检查一下磁盘,尤其是最后的数据分区,恢复的时候一般都会有分区表错误,貌似只有在SSH 里面执行的才是正常的,原因未知。至于下面的分区大小调整,如果能在SSH 中处理的话,是最好的,问题最少。 下面是SSH 处理的SHELL 记录

WDMyCloud:~# df 
Filesystem      1K-blocks   Used  Available Use% Mounted on
rootfs            1968336 482148    1386200  26% /
/dev/root         1968336 482148    1386200  26% /
tmpfs               23056    336      22720   2% /run
tmpfs               40960      4      40956   1% /run/lock
tmpfs               10240      0      10240   0% /dev
tmpfs                5120      0       5120   0% /run/shm
tmpfs              102400    196     102204   1% /tmp
/dev/root         1968336 482148    1386200  26% /var/log.hdd
ramlog-tmpfs        20480   1988      18492  10% /var/log
/dev/sda4      2879644604 594272 2820539292   1% /DataVolume
/dev/root         1968336 482148    1386200  26% /nfs/Public
/dev/root         1968336 482148    1386200  26% /nfs/SmartWare
/dev/root         1968336 482148    1386200  26% /nfs/TimeMachineBackup

WDMyCloud:~# umount /dev/sda4
WDMyCloud:~# umount /dev/root
WDMyCloud:~# umount /dev/root
WDMyCloud:~# umount /dev/root
WDMyCloud:~# umount /dev/root

WDMyCloud:~# df
Filesystem     1K-blocks   Used Available Use% Mounted on
rootfs           1968336 482148   1386200  26% /
/dev/root        1968336 482148   1386200  26% /
tmpfs              23056    336     22720   2% /run
tmpfs              40960      4     40956   1% /run/lock
tmpfs              10240      0     10240   0% /dev
tmpfs               5120      0      5120   0% /run/shm
tmpfs             102400    196    102204   1% /tmp
ramlog-tmpfs       20480   1988     18492  10% /var/log

WDMyCloud:~# e2fsck /dev/sda4
e2fsck 1.42.5 (29-Jul-2012)
/dev/sda4 contains a file system with errors, check forced.
Pass 1: Checking inodes, blocks, and sizes
Journal inode is not in use, but contains data.  Clear<y>? yes
Pass 2: Checking directory structure
Entry 'cache' in / (2) has deleted/unused inode 92798977.  Clear<y>? yes
Entry 'shares' in / (2) has deleted/unused inode 51642369.  Clear<y>? yes
Entry 'backup' in / (2) has deleted/unused inode 28049409.  Clear<y>? yes
Pass 3: Checking directory connectivity
Pass 4: Checking reference counts
Inode 2 ref count is 6, should be 3.  Fix<y>? yes
Pass 5: Checking group summary information
Block bitmap differences:  -(33808--33814) -(34304--64646) -(65536--98303) -(100352--163839) -(165888--229375) -(231424--294911) -(296960--524287) -(57679904--57679911) -(68165664--68165676) -(68165680--68165687) -518004768
Fix<y>? yes
Free blocks count wrong for group #1 (1393, counted=31743).
Fix<y>? yes
Free blocks count wrong for group #2 (0, counted=32768).
Fix<y>? yes
Free blocks count wrong for group #3 (1023, counted=31743).
Fix<y>? yes
Free blocks count wrong for group #4 (29696, counted=32768).
Fix<y>? yes
Free blocks count wrong for group #3424 (24543, counted=24544).
Fix<y>? yes
Free blocks count wrong for group #6304 (24526, counted=24544).
Fix<y>? yes
Free blocks count wrong for group #6305 (32754, counted=32768).
Fix<y>? yes
Free blocks count wrong for group #7425 (0, counted=32768).
Fix<y>? yes
Free blocks count wrong for group #11328 (24513, counted=24544).
Fix<y>? yes
Free blocks count wrong for group #11329 (32626, counted=32768).
Fix<y>? yes
Free blocks count wrong (719762583, counted=719892467).
Fix<y>? yes
Free inodes count wrong for group #3424 (8191, counted=8192).
Fix<y>? yes
Directories count wrong for group #3424 (1, counted=0).
Fix<y>? yes
Free inodes count wrong for group #6304 (8174, counted=8192).
Fix<y>? yes
Directories count wrong for group #6304 (15, counted=0).
Fix<y>? yes
Free inodes count wrong for group #11328 (8084, counted=8192).
Fix<y>? yes
Directories count wrong for group #11328 (31, counted=0).
Fix<y>? yes
Free inodes count wrong (182853494, counted=182853621).
Fix<y>? yes

/dev/sda4: ***** FILE SYSTEM WAS MODIFIED *****
/dev/sda4: 11/182853632 files (0.0% non-contiguous), 11495550/731388017 blocks
WDMyCloud:~# parted
GNU Parted 2.3
Using /dev/sda
Welcome to GNU Parted! Type 'help' to view a list of commands.
(parted) p                                                                
Error: The backup GPT table is corrupt, but the primary appears OK, so that will
be used.
OK/Cancel? OK                                                             
Warning: Not all of the space available to /dev/sda appears to be used, you can
fix the GPT to use all of the space (an extra 1953504000 blocks) or continue
with the current setting? 
Fix/Ignore? Fix                                                           
Model: ATA WDC WD40EFRX-68W (scsi)
Disk /dev/sda: 4001GB
Sector size (logical/physical): 512B/4096B
Partition Table: gpt

Number  Start   End     Size    File system     Name     Flags
 3      15.7MB  528MB   513MB   linux-swap(v1)  primary
 1      528MB   2576MB  2048MB  ext3            primary  raid
 2      2576MB  4624MB  2048MB  ext3            primary  raid
 5      4624MB  4724MB  99.6MB                  primary
 6      4724MB  4824MB  101MB                   primary
 7      4824MB  4826MB  1049kB                  primary
 8      4826MB  4828MB  2097kB                  primary
 4      4828MB  3001GB  2996GB  ext4            primary

(parted) unit                                                             
Unit?  [compact]? s                                                       
(parted) p                                                                
Model: ATA WDC WD40EFRX-68W (scsi)
Disk /dev/sda: 7814037168s
Sector size (logical/physical): 512B/4096B
Partition Table: gpt

Number  Start     End          Size         File system     Name     Flags
 3      30720s    1032191s     1001472s     linux-swap(v1)  primary
 1      1032192s  5031935s     3999744s     ext3            primary  raid
 2      5031936s  9031679s     3999744s     ext3            primary  raid
 5      9031680s  9226239s     194560s                      primary
 6      9226240s  9422847s     196608s                      primary
 7      9422848s  9424895s     2048s                        primary
 8      9424896s  9428991s     4096s                        primary
 4      9428992s  5860533134s  5851104143s  ext4            primary

(parted) rm 4                                                             
(parted) mkpart                                                           
Partition name?  []?                                                      
File system type?  [ext2]? ext4                                           
Start? 9428992s     # 开始扇区的是原来4号分区的开始扇区   
End? 7814037167s    # 终止扇区的是执行 p 命令时候返回的磁盘总扇区数7814037168s-1                                                      
(parted) q                      
                                          
Information: You may need to update /etc/fstab.                           

WDMyCloud:~# parted
GNU Parted 2.3
Using /dev/sda
Welcome to GNU Parted! Type 'help' to view a list of commands.
(parted) p                                                                
Model: ATA WDC WD40EFRX-68W (scsi)
Disk /dev/sda: 4001GB
Sector size (logical/physical): 512B/4096B
Partition Table: gpt

Number  Start   End     Size    File system     Name     Flags
 3      15.7MB  528MB   513MB   linux-swap(v1)  primary
 1      528MB   2576MB  2048MB  ext3            primary  raid
 2      2576MB  4624MB  2048MB  ext3            primary  raid
 5      4624MB  4724MB  99.6MB                  primary
 6      4724MB  4824MB  101MB                   primary
 7      4824MB  4826MB  1049kB                  primary
 8      4826MB  4828MB  2097kB                  primary
 4      4828MB  3996GB  3991GB  ext4

(parted) check 4                                                          
WARNING: you are attempting to use parted to operate on (check) a file system.
parted's file system manipulation code is not as robust as what you'll find in
dedicated, file-system-specific packages like e2fsprogs.  We recommend
you use parted only to manipulate partition tables, whenever possible.
Support for performing most operations on most types of file systems
will be removed in an upcoming release.
Warning: Partition 4 is 3991GB, but the file system is 2996GB.            
Ignore/Cancel? Ignore                                                     
Error: File system has an incompatible feature enabled.  Compatible features are
has_journal, dir_index, filetype, sparse_super and large_file.  Use tune2fs or
debugfs to remove features.
(parted) q     
                                                           
WDMyCloud:~# resize2fs /dev/sda4
resize2fs 1.42.5 (29-Jul-2012)
Resizing the filesystem on /dev/sda4 to 974397394 (4k) blocks.
The filesystem on /dev/sda4 is now 974397394 blocks long.

WDMyCloud:~# reboot

最好升级一下 usb 接口的程序版本,新版本貌似修正了大文件拷贝会死机的问题

$ sudo apt-get update

$ sudo apt-get install udev

7.再次拆卸硬盘,用Linux 中的 gparted 来根据实际硬盘的大小来调整硬盘,比如,我的是4T 版本的,刷完之后,会有1T 的空白分区,这个时候可以通过gparted 来调整到整个硬盘。 (注意,外面调整分区可能导致不能启动,原因未知,因此恐怕要多尝试几次

8.装回硬盘,重新启动,最好恢复一下出厂设置。

  • 如果分区都还在,又不想损坏数据,可以试试如下方法

1.下载最新的固件版本比如 http://download.wdc.com/nas/WDMyCloud-030104-139-20131028.zip 解压缩数据 从CacheVolume 目录中找到 rootfs.img 文件,大约2G 的样子,解压缩到某个目录即可。

2.按照上文方法拆卸硬盘,并挂载到Ubuntu。

3.在磁盘管理器中打开如下界面,还原到的分区为管理器中现实Raid 的两个分区中,两个分区逐个还原。

original

选择 "Restore Disk Image"

original2

上面的方法有些人可以恢复成功,有些没有办法恢复成功,中间的差别一般在于有些人机器上安装了mdadm。如下图所示,磁盘挂载后会识别出"2.0GB RAID-1阵列",如果下面的挂载位置不是"/dev/md/0",而是显示"/dev/md127"或者"/dev/md126",那么,即使什么都不操作,直接装回去,也可能发现WDMyCloud不能正常启动了。
 这个原因是由于机器上安装的mdadm无意之间修改了部分内容,导致WDMyCloud无法识别。解决办法是在电脑上重建这个"2.0GB RAID-1阵列",以系统会把磁盘挂载到/dev/sdb为例子,方法如下:

$ sudo mdadm --stop /dev/md0

$ sudo mdadm -C /dev/md0 --metadata=0.9 -l 1 -n 2 /dev/sdb1 /dev/sdb2

重建完成后,挂载位置被修正为"/dev/md/0",然后通过在"2.0GB RAID-1阵列"上点击"对分区映像恢复"(英文应该是"Restore Disk Image")进行镜像的恢复工作。

恢复完成后,先执行

$ sudo mdadm --stop /dev/md0

停止阵列,然后点击顶部的"Power Off"按钮,移除磁盘。如下图:

上面的操作完成后,一般会出现磁盘错误,建议进行磁盘检查,具体操作过程如下:

$ sudo umount /dev/sda4

$ sudo umount /dev/sda4

$ sudo umount /dev/sda4

#查看挂载的分区
$ df 
文件系统            1K-块       已用      可用 已用% 挂载点
rootfs            1968336     744964   1123384   40% /
/dev/root         1968336     744964   1123384   40% /
tmpfs               40960       4160     36800   11% /run
tmpfs               40960         64     40896    1% /run/lock
tmpfs               10240          0     10240    0% /dev
tmpfs                5120          0      5120    0% /run/shm
tmpfs              102400       9280     93120   10% /tmp
/dev/root         1968336     744964   1123384   40% /var/log.hdd
ramlog-tmpfs        40960       6464     34496   16% /var/log
/dev/sda4      3841069352 2937611696 825411592   79% /CacheVolume

$ lsof | grep CacheVolume

$ kill -9 $(pidof twonkystarter)

$ kill -9 $(pidof twonkyserver)

$ kill -9 $(pidof forked-daapd)

$ sudo umount /dev/sda4

$ fsck -y /dev/sda4

上述操作完成后,如果首页容量部分一直显示0KB,则参考WD MyCloud拆硬盘恢复系统后容量部分显示0KB

参考链接


WD My Book Live 离线升级固件

MBL通电后登录Web管理界面,第一件事就是要求升级固件,点了确定后才发现下载进度堪比蜗牛,一个半小时进度大约50%。升级不完还没办法进一步设置,实在无法忍了,边下边找办法看能不能快速搞定吧。

MBL官网上没找着固件下载链接,只见一行小字写着现在已经不再支持手动升级固件。肯定会有办法的,能自动升级必须可以手动。

用SSH连接上,果然在 /usr/local/sbin 目录下发现了一堆设置相关脚本,其中有两个:

-rwxr-xr-x 1 root root  5865 Feb 16 02:24 updateFirmwareFromFile.sh
-rwxr-xr-x 1 root root  2364 Aug 11  2012 updateFirmwareToLatest.sh

第一个脚本看名字就知道干啥用的,正是下载好固件手动升级用的,等下再细看怎么用;直接看第二个吧,真相来了,第24行代码直接告诉你怎么拿到最新固件的下载地址:

$ curl -4 "`cat /tmp/update_url`" > ${update_file} 2>/tmp/fw_download_status

在shell中敲入下面的命令:

$ cat /tmp/update_url

下载链接是不是已经出来了(前提是Web管理界面里的自动下载还在进行,如果已经没有执行或已经取消,/tmp/update_url 文件是不存在的,你知道该怎么办)。接下来的事情更加简单了,用迅雷或是QQ旋风等任意工具将固件下载回来,应该是一个.deb文件,然后通过 winscp或是文件共享把它放到MBL的目录里,MBL共享用的 /shares/Public 目录就挺好,最后在 /usr/local/sbin 目录下执行:

$ ./updateFirmwareFromFile.sh /shares/Public/文件名

你将会惊奇地发现Web管理界面上已经显示出了升级进度,耐心等待……几分钟就好。

参考链接 http://i.migege.com/my-book-live-manual-updating.html

Method类invoke方法的使用

java.lang.reflect.Method
public Object invoke(Object obj,Object args[])
参数:
    obj - 从中调用底层方法的对象,必须是实例化的对象
    args - 用于方法调用的参数,是个Object数组,因为参数有可能有多个
返回:
    使用参数 args 在 obj 上指派该对象所表示方法的结果

例如:

String result = (String)method.invoke(obj , sql);

执行obj的method方法(参数为sql),返回String类型结果

args参数可以为空,就是对应方法没有参数

如:

new Car().getBM() ---- method.invoke( obj );//method为getBM,obj为Car类

obj可以为空,但必填null,表示同类中的公用方法,

如:

getName(type) ---- method.invoke(null,args);//method为getName,args为type

参数args是个Object数组,即使只有一个参数,也要建object数组

如:

getName(String aaa , String bbb )----需要2个参数,method.invoke(null , new Object[] {aaa , bbb});//aaa , bbb分别为getName的2个参数

注意:obj必须是实例化的对象,如果有对应的方法名,就可以实例化

部分代码如下:

Class clz = getClass(clzName);
Object obj = null;
//实例化对象
try {
    obj = clz.newInstance();
} catch (InstantiationException e1) {
    e1.printStackTrace();
} catch (IllegalAccessException e1) {
    e1.printStackTrace();
}

//invoke,执行对应类的method方法
try {
    method.invoke(obj, new Object[]{elValue.trim()});
} catch (IllegalArgumentException e) {
    e.printStackTrace();
} catch (IllegalAccessException e) {
    e.printStackTrace();
} catch (InvocationTargetException e) {
    e.printStackTrace();
}

getClass在下面:

public static Class getClass(String className) {
    Class clz = null;
    try {
        clz = Class.forName(className);
    } catch (ClassNotFoundException e) {
        e.printStackTrace();
    }
    return clz;
}

newInstance() 的参数版本与无参数版本详解

通过反射创建新的类示例,有两种方式:

Class.newInstance()
Constructor.newInstance()

以下对两种调用方式给以比较说明:
Class.newInstance() 只能够调用无参的构造函数,即默认的构造函数;
Constructor.newInstance() 可以根据传入的参数,调用任意构造构造函数。Class.newInstance() 抛出所有由被调用构造函数抛出的异常。

Class.newInstance() 要求被调用的构造函数是可见的,也即必须是public类型的;

Constructor.newInstance() 在特定的情况下,可以调用私有的构造函数。

Class A(被调用的示例):

public class A {
	private A() {
		System.out.println("A's constructor is called.");
	}

	private A(int a, int b) {
		System.out.println("a:" + a + " b:" + b);
	}
}

Class B(调用者):

public class B { 
	public static void main(String[] args) { 
		B b=new B(); 
		out.println("通过Class.NewInstance()调用私有构造函数:"); 
		b.newInstanceByClassNewInstance(); 
		out.println("通过Constructor.newInstance()调用私有构造函数:"); 
		b.newInstanceByConstructorNewInstance(); 
	} 
	/*通过Class.NewInstance()创建新的类示例*/ 
	private void newInstanceByClassNewInstance(){ 
		try {/*当前包名为reflect,必须使用全路径*/ 
			A a=(A)Class.forName("reflect.A").newInstance(); 
		} catch (Exception e) { 
			out.println("通过Class.NewInstance()调用私有构造函数【失败】"); 
		}
	}

	/*通过Constructor.newInstance()创建新的类示例*/ 
	private void newInstanceByConstructorNewInstance(){ 
		try {/*可以使用相对路径,同一个包中可以不用带包路径*/ 
			Class c=Class.forName("A"); 
			/*以下调用无参的、私有构造函数*/ 
			Constructor c0=c.getDeclaredConstructor(); 
			c0.setAccessible(true); 
			A a0=(A)c0.newInstance(); 
			/*以下调用带参的、私有构造函数*/ 
			Constructor c1=c.getDeclaredConstructor(new Class[]{int.class,int.class}); 
			c1.setAccessible(true); 
			A a1=(A)c1.newInstance(new Object[]{5,6}); 
		} catch (Exception e) { 
			e.printStackTrace(); 
		} 
	} 
}

输出结果如下:

通过Class.NewInstance()调用私有构造函数:
通过Class.NewInstance()调用私有构造函数【失败】
通过Constructor.newInstance()调用私有构造函数:
A's constructor is called.
a:5 b:6

说明方法newInstanceByClassNewInstance调用失败,而newInstanceByConstructorNewInstance则调用成功。如果被调用的类的构造函数为默认的构造函数,采用Class.newInstance()则是比较好的选择,一句代码就OK;如果被调用的类带参构造函数、私有构造函数,就需要采用Constractor.newInstance(),两种情况视使用情况而定。
不过Java Totorial中推荐采用Constractor.newInstance()。

参考 http://xiaohuafyle.iteye.com/blog/1607258