ubuntu12.04编译Android 4.0.3 Source+Kernel记

Mac OS X Lion下编译Android Source错误连连,无奈还得用Ubuntu,最近ubuntu发布了LTS版本12.04,于是乎就用12.04了。由于Mac OS本身就源于BSD Unix,装ubuntu多系统有点浪费硬盘,就用虚拟机VMware Fusion装了ubuntu。

一、增大虚拟硬盘
但是麻烦又来了,VMware Fusion默认分给ubuntu的最大虚拟硬盘空间只有20G,而Android官网上说,“The source download is approximately 6GB in size. You will need 25GB free to complete a single build, and up to 90GB (or more) for a full set of builds”,于是还得增大虚拟硬盘的空间。方法如下:1、虚拟机->设置->硬盘,然后将磁盘大小改到你想要的大小,这里我的是120G。

2、将新增的部分格式化。
这里我在ubuntu里直接用了GParted这个工具,你可以使用如下命令安装:

1
sudo apt-get install gparted

剩下的操作就简单了,需要将未格式化的部分格式化为ext4格式,然后挂在就行了。其实就相当于你原先只有C盘的Windows增添了一个D盘。

二、设置编译环境
解决了空间的问题,就需要按照Android官网上的教程一步一步做了。在ubuntu12.04下,只需三步:
1、安装依赖包,其实就是官网上那一步:

1
sudo apt-get install git-core gnupg flex bison gperf build-essential zip curl libc6-dev libncurses5-dev:i386 x11proto-core-dev libx11-dev:i386 libreadline6-dev:i386 libgl1-mesa-dev:i386 g++-multilib mingw32 openjdk-6-jdk tofrodos python-markdown libxml2-utils xsltproc zlib1g-dev:i386

2、安装sun-java
按照官网上说的,openjdk编译有问题,所以必须得安装sun官方的JDK。先从sun官网上下载JDK,2.3或者更新的版本用java6,2.2及以前的版本用java5。我们的版本是4.0.3,所以应该下载jdk6,这里我们用的是jdk-6u22-linux-i586.bin。先将jdk-6u22-linux-i586.bin copy到/opt,然后安装即可。

1
2
3
cp jdk-6u22-linux-i586.bin /opt
cd /opt
./jdk-6u22-linux-i586.bin

然后修改环境变量:

1
2
3
sudo vim /etc/environment
//将/opt/jdk1.6.0_22/bin:/opt/jdk1.6.0_22/lib:/opt/jdk1.6.0_22添加到PATH最前面,结果类似于
PATH="/opt/jdk1.6.0_22/bin:/opt/jdk1.6.0_22/lib:/opt/jdk1.6.0_22:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games"

注意:必须把路径加载最前面,以防止系统使用openjdk,或者你把openjdk卸载也行。
3、将默认的gcc4.6换成gcc4.4,太高的gcc版本导致出现各种错误,比如error: “_FORTIFY_SOURCE” redefined [-Werror]。

1
2
3
4
5
sudo apt-get install gcc-4.4
sudo apt-get install g++-4.4
cd /usr/bin
sudo ln -s gcc-4.4 gcc
sudo ln -s g++-4.4 g++

三、下载编译
剩下的就是下载Android Source,这个按官网上照做就行,可以参照前面的一篇博客。编译源代码:

1
2
3
. build/envsetup.sh
lunch full_x86-eng
make -j8

那么怎么下载Android内核呢?我的测试机为Nenux S,因此以S为例:

1
2
3
4
5
git clone https://android.googlesource.com/kernel/samsung.git
//查看版本
git bransh -a
//这里我选择了remotes/origin/android-samsung-3.0-ics-mr1
git checkout -b android-samsung-3.0-ics-mr1 origin/android-samsung-3.0-ics-mr1

最后编译内核,按照官网说的做就行。

1
2
3
4
5
6
7
//设置交叉编译工具路径,具体看你把prebuilt/linux-x86/toolchain/arm-eabi-4.4.3/bin放哪了
export PATH=$(pwd)/prebuilt/linux-x86/toolchain/arm-eabi-4.4.3/bin:$PATH
export ARCH=arm
export SUBARCH=arm
export CROSS_COMPILE=arm-eabi-
make herring_defconfig
make

–END–

五子棋算法-python实现

人工智能课的实验——用python实现五子棋,这里采用了alpha-beta极大极小搜索算法,并用贪心做了一下优化。需要的同学可以拿去,可以参考另一篇博文

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
#coding=utf-8
#Author: Yan
#Date:   2012/4/18

MAX_LINE = 15

EMPTY = '0'
MYSELF = '1'
RIVAL = '2'

INIT_MAX = 2147483647

#棋型
FIVE = 1
FOUR = 2
SLEEP_FOUR = 3
THREE = 4
SLEEP_THREE = 5
TWO = 6
SLEEP_TWO = 7

UNANALYSED = 0
ANALYSED = 10

WIN = 1
LOSE = -1
TIE = 0

#越往中心估值越大
NODE_VALUE  = \
[ \
        [ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ] ,\
        [ 0 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 0 ] ,\
        [ 0 , 1 , 2 , 2 , 2 , 2 , 2 , 2 , 2 , 2 , 2 , 2 , 2 , 1 , 0 ] ,\
        [ 0 , 1 , 2 , 3 , 3 , 3 , 3 , 3 , 3 , 3 , 3 , 3 , 2 , 1 , 0 ] ,\
        [ 0 , 1 , 2 , 3 , 4 , 4 , 4 , 4 , 4 , 4 , 4 , 3 , 2 , 1 , 0 ] ,\
        [ 0 , 1 , 2 , 3 , 4 , 5 , 5 , 5 , 5 , 5 , 4 , 3 , 2 , 1 , 0 ] ,\
        [ 0 , 1 , 2 , 3 , 4 , 5 , 6 , 6 , 6 , 5 , 4 , 3 , 2 , 1 , 0 ] ,\
        [ 0 , 1 , 2 , 3 , 4 , 5 , 6 , 7 , 6 , 5 , 4 , 3 , 2 , 1 , 0 ] ,\
        [ 0 , 1 , 2 , 3 , 4 , 5 , 6 , 6 , 6 , 5 , 4 , 3 , 2 , 1 , 0 ] ,\
        [ 0 , 1 , 2 , 3 , 4 , 5 , 5 , 5 , 5 , 5 , 4 , 3 , 2 , 1 , 0 ] ,\
        [ 0 , 1 , 2 , 3 , 4 , 4 , 4 , 4 , 4 , 4 , 4 , 3 , 2 , 1 , 0 ] ,\
        [ 0 , 1 , 2 , 3 , 3 , 3 , 3 , 3 , 3 , 3 , 3 , 3 , 2 , 1 , 0 ] ,\
        [ 0 , 1 , 2 , 2 , 2 , 2 , 2 , 2 , 2 , 2 , 2 , 2 , 2 , 1 , 0 ] ,\
        [ 0 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 0 ] ,\
        [ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ] \
]

#对每一种状态所对应的分数
STATE_SCORE = [ 0 , 100000 , 10000 , 5000 , 3000 , 500 , 100 , 50 ]

#记录走的一步
class Node( object ):
    def __init__( self ):
        self.x = -1
        self.y = -1
        self.value = 0
        self.win = TIE

#评估值类
class Evaluate( object ):
    def __init__( self ):
        self.numOfState = [ [ 0 for i in range( 0 , 8 ) ] for j in range( 0 , 2  ) ]
    def analyseLine( self , player , line ):
        enemy = RIVAL if player == MYSELF else MYSELF
        current_player = int( player ) - 1
        line_size = len( line )
        nodeStates = [ UNANALYSED for i in range( 0 , MAX_LINE ) ]
       
        leftEdge = -1
        rightEdge = -1
        for i in range( 0 , line_size ):
            if line[ i ] == player and nodeStates[ i ] == UNANALYSED:
                leftEdge = rightEdge = i
                #向左搜索
                while( leftEdge >= 0 ):
                    if line[ leftEdge ] != player:
                        break
                    leftEdge -= 1
                #向右搜索
                while( rightEdge < line_size ):
                    if line[ rightEdge ] != player:
                        break
                    rightEdge += 1
                leftEdge += 1
                rightEdge -= 1
                for index in range( leftEdge , rightEdge + 1 , 1 ):
                    nodeStates[ index ] = ANALYSED
                if leftEdge == rightEdge:
                    nodeStates[ leftEdge ] = UNANALYSED
                #如果是5连 xxxxx
                if rightEdge - leftEdge > 3:
                    self.numOfState[ current_player ][ FIVE ] += 1
                #如果是4连
                elif rightEdge - leftEdge == 3:
                    #如果是活四
                    if ( leftEdge > 0 and rightEdge < line_size - 1 and line[ leftEdge - 1 ] == EMPTY and line[ rightEdge + 1 ] == EMPTY ):
                        self.numOfState[ current_player ][ FOUR ] += 1
                    #如果是冲四,则有且仅有一侧空,另一侧或者为边界或者为敌方棋子 _xxxxo或者oxxxx_
                    elif ( ( ( leftEdge == 0 or (leftEdge > 0 and line[ leftEdge - 1 ] == enemy ) ) and (rightEdge < line_size - 1 and line[ rightEdge + 1 ] == EMPTY) ) or ( (rightEdge == line_size - 1 or ( rightEdge < line_size - 1 and line[ rightEdge + 1 ] == enemy )) and ( leftEdge > 0 and line[ leftEdge - 1 ] == EMPTY) ) ):
                        self.numOfState[ current_player ][ SLEEP_FOUR ] += 1
                #如果是3连
                elif rightEdge - leftEdge == 2:
                    #如果是冲四 xxx_x或x_xxx
                    if ( (leftEdge > 1 and line[ leftEdge - 2 ] == player and nodeStates[ leftEdge - 2 ] == UNANALYSED and line[ leftEdge - 1 ] == EMPTY) or (rightEdge < line_size - 2 and line[ rightEdge + 1 ] == EMPTY and line[ rightEdge + 2 ] == player and nodeStates[ rightEdge + 2 ] == UNANALYSED ) ):
                        self.numOfState[ current_player ][ SLEEP_FOUR ] += 1   
                    #如果是活三 _xxx__或__xxx_
                    elif ( leftEdge > 0 and rightEdge < line_size - 1 and line[ leftEdge - 1 ] == EMPTY and line[ rightEdge + 1 ] == EMPTY and ( (leftEdge > 1 and line[ leftEdge - 2 ] == EMPTY) or ( rightEdge < line_size - 2 and line[ rightEdge + 2 ] == EMPTY ) ) ):
                        self.numOfState[ current_player ][ THREE ] += 1
                    #如果是眠三
                    else:
                        #第一种形式 oxxx__或__xxxo
                        if( ((leftEdge == 0 or (leftEdge > 0 and line[ leftEdge - 1 ] == enemy)) and ( rightEdge < line_size - 2 and line[ rightEdge + 1 ] == EMPTY and line[ rightEdge + 2 ] == EMPTY )) or ( (leftEdge > 1 and line[ leftEdge - 1 ] == EMPTY and line[ leftEdge - 2 ] == EMPTY) and (rightEdge == line_size - 1 or (rightEdge < line_size - 1 and line[ rightEdge + 1 ] == enemy ) ) ) ):
                            self.numOfState[ current_player ][ SLEEP_THREE ] += 1
                        #第二种形式o_xxx_o
                        elif ( leftEdge > 0 and line[ leftEdge - 1 ] == EMPTY and rightEdge < line_size - 1 and line[ rightEdge + 1 ] == EMPTY and ( leftEdge == 1 or (leftEdge > 1 and line[ leftEdge - 2 ] == enemy)) and ( rightEdge == line_size - 2 or ( rightEdge < line_size - 2 and line[ rightEdge + 2 ] == enemy ))):
                            self.numOfState[ current_player ][ SLEEP_THREE ] += 1
                #如果是2连
                elif rightEdge - leftEdge == 1:
                    #冲四 oxx_xx或xx_xxo
                    if ( ((leftEdge == 0 or (leftEdge > 0 and line[ leftEdge - 1 ] == enemy )) and ( rightEdge < line_size - 3 and line[ rightEdge + 1 ] == EMPTY and line[ rightEdge + 2 ] == player and nodeStates[ rightEdge + 2 ] == UNANALYSED and line[ rightEdge + 3 ] == player and nodeStates[ rightEdge + 3 ] == UNANALYSED )) or ( (rightEdge == line_size - 1 or (rightEdge < line_size - 1 and line[ rightEdge + 1 ] == enemy )) and leftEdge > 2 and line[ leftEdge - 1 ] == EMPTY and line[ leftEdge - 2 ] == player and nodeStates[ leftEdge - 2 ] == UNANALYSED and line[ leftEdge - 3 ] == player and nodeStates[ leftEdge - 3 ] == UNANALYSED ) ):
                        self.numOfState[ current_player ][ SLEEP_FOUR ] += 1
                    #如果是跳活三 _xx_x_或_x_xx_
                    elif ( leftEdge > 0 and line[ leftEdge - 1 ] == EMPTY and rightEdge < line_size - 1 and line[ rightEdge + 1 ] == EMPTY and ( (rightEdge < line_size - 3 and line[ rightEdge + 2 ] == player and nodeStates[ rightEdge + 2 ] == UNANALYSED and line[ rightEdge + 3 ] == EMPTY ) or ( leftEdge > 2 and line[ leftEdge - 2 ] == player and nodeStates[ leftEdge - 2 ] == UNANALYSED and line[ leftEdge - 3 ] == EMPTY ) )):
                        self.numOfState[ current_player ][ THREE ] += 1
                    #如果是眠三 oxx_x_或_x_xxo
                    elif ( ( (leftEdge == 0 or (leftEdge > 0 and line[ leftEdge - 1 ] == enemy )) and rightEdge < line_size - 3 and line[ rightEdge + 1 ] == EMPTY and line[ rightEdge + 2 ] == player and nodeStates[ rightEdge + 2 ] == UNANALYSED and line[ rightEdge + 3 ] == EMPTY) or ( ( rightEdge == line_size - 1 or ( rightEdge < line_size - 1 and line[ rightEdge + 1 ] == enemy )) and leftEdge > 2 and line[ leftEdge - 1 ] == EMPTY and line[ leftEdge - 2 ] == player and nodeStates[ leftEdge - 2 ] == UNANALYSED and line[ leftEdge - 3 ] == EMPTY ) ):
                        self.numOfState[ current_player ][ SLEEP_THREE ] += 1
                    #如果是眠三 oxx__x或x__xxo
                    elif ( ( (leftEdge == 0 or (leftEdge > 0 and line[ leftEdge - 1 ] == enemy )) and rightEdge < line_size - 3 and line[ rightEdge + 1 ] == EMPTY and line[ rightEdge + 2 ] == EMPTY and line[ rightEdge + 3 ] == player and nodeStates[ rightEdge + 3 ] == UNANALYSED ) or ( ( rightEdge == line_size - 1 or ( rightEdge < line_size - 1 and line[ rightEdge + 1 ] == enemy )) and leftEdge > 2 and line[ leftEdge - 1 ] == EMPTY and line[ leftEdge - 2 ] == EMPTY and line[ leftEdge - 3 ] == player and nodeStates[ leftEdge - 3 ] == UNANALYSED ) ) :
                        self.numOfState[ current_player ][ SLEEP_THREE ] += 1
                    #如果是眠三 ox__xx或xx__xo
                    elif ( (leftEdge > 2 and line[ leftEdge - 1 ] == EMPTY and line[ leftEdge - 2 ] == EMPTY and line[ leftEdge - 3 ] == player  and ( leftEdge == 3 or ( leftEdge > 3 and line[ leftEdge - 4 ] == enemy )) ) or (rightEdge < line_size - 3 and line[ rightEdge + 1 ] == EMPTY and line[ rightEdge + 2 ] == EMPTY and line[ rightEdge + 3 ] == player and ( rightEdge == line_size - 4 or ( rightEdge < line_size - 4 and line[ rightEdge + 4 ] == enemy )))):
                        self.numOfState[ current_player ][ SLEEP_THREE ] += 1
                    #如果是活二 __xx__
                    elif ( leftEdge > 1 and rightEdge < line_size - 2 and line[ leftEdge - 1 ] == EMPTY and line[ leftEdge - 2 ] == EMPTY and line[ rightEdge + 1 ] == EMPTY and line[ rightEdge + 2 ] == EMPTY ):
                        self.numOfState[ current_player ][ TWO ] += 1
                    #如果是眠二 oxx___或___xxo
                    elif ( ( (leftEdge == 0 or (leftEdge > 0 and line[ leftEdge - 1 ] == enemy ) ) and rightEdge < line_size - 3 and line[ rightEdge + 1 ] == EMPTY and line[ rightEdge + 2 ] == EMPTY and line[ rightEdge + 3 ] == EMPTY ) or ( ( rightEdge == line_size - 1 or ( rightEdge < line_size - 1 and line[ rightEdge + 1 ] == enemy )) and leftEdge > 2 and line[ leftEdge - 1 ] == EMPTY and line[ leftEdge - 2 ] == EMPTY and line[ leftEdge - 3 ] == EMPTY)):
                        self.numOfState[ current_player ][ SLEEP_TWO ] += 1


    def findStateNum( self , board ):
        #水平和垂直方向搜索
        for i in range( 0 , MAX_LINE ):
            src_row = src_col = ''
            for j in range( 0 , MAX_LINE ):
                src_row += board[ i ][ j ]
                src_col += board[ j ][ i ]
                self.analyseLine( MYSELF , src_row )
                self.analyseLine( MYSELF , src_col )
                self.analyseLine( RIVAL , src_row )
                self.analyseLine( RIVAL , src_col )
        #左下-右上搜索
        for sum in range( 4 , 25 , 1 ):
            src = ''
            i = sum if sum < = 14 else 14
            j = sum - i
            while( i >= 0 and j < = 14 ):
                src += board[ i ][ j ]
                i -= 1
                j += 1
            self.analyseLine( RIVAL , src )
            self.analyseLine( MYSELF , src )
        #左上-右下搜索
        for sub in range( 10 , -11 , -1 ):
            src = ''  
            i = sub if sub >= 0 else 0
            j = i - sub
            while( i < = 14 and j <= 14 ):
                src += board[ i ][ j ]  
                i += 1
                j += 1
            self.analyseLine( MYSELF , src )  
            self.analyseLine( RIVAL , src )  
    #估值函数  
    def getValue( self , player , board ):
        tmpNode = Node()
        my_score = rival_score = 0
        self.numOfState = [ [ 0 for i in range( 0 , 8 ) ] for j in range( 0 , 2  ) ]
        self.findStateNum( board )
        for i in range( 8 ):
            tmp = self.numOfState[ 0 ][ i ] * STATE_SCORE[ i ]
            my_score += self.numOfState[ 0 ][ i ] * STATE_SCORE[ i ]
            rival_score += self.numOfState[ 1 ][ i ] * STATE_SCORE[ i ]
        current_player = int( player ) - 1
        other_player = 1 - current_player
        if self.numOfState[ other_player ][ FIVE ] != 0:
            tmpNode.value = -200000
            tmpNode.win = LOSE
            return tmpNode
        elif self.numOfState[ current_player ][ FIVE ] != 0:
            tmpNode.value = 200000
            tmpNode.win = WIN
            return tmpNode
        elif self.numOfState[ other_player ][ FOUR ] != 0 or self.numOfState[ other_player ][ SLEEP_FOUR ] != 0:
            tmpNode.value = -180000
            tmpNode.win = LOSE
            return tmpNode
        elif self.numOfState[ current_player ][ FOUR ] != 0:
            tmpNode.value = 180000
            tmpNode.win = WIN
            return tmpNode
        elif ( self.numOfState[ current_player ][ SLEEP_FOUR ] + self.numOfState[ current_player ][ THREE ] > 1 ) and ( self.numOfState[ other_player ][ THREE ] == 0 ) and ( self.numOfState[ other_player ][ FOUR ] == 0 ) and ( self.numOfState[ other_player ][ SLEEP_FOUR ] == 0 ):
            tmpNode.value = 100000
            tmpNode.win = WIN
            return tmpNode
        for i in range( 0 , MAX_LINE ):
            for j in range( 0 , MAX_LINE ):
                if board[ i ][ j ] == MYSELF:
                    my_score += NODE_VALUE[ i ][ j ]
                elif board[ i ][ j ] == RIVAL:
                    rival_score += NODE_VALUE[ i ][ j ]
        tmpNode.value = ( my_score - rival_score ) if player == MYSELF else ( rival_score - my_score )
        return tmpNode 
#主要类
class Search( object ):
    #depth:搜索深度 numofgoodnodes:搜索广度
    def __init__( self , depth , numOfGoodNodes , chessBoard ):
        self.depth = depth
        self.numOfGoodNodes = numOfGoodNodes
        self.chessBoard = chessBoard
        self.bestMove = Node()
        self.evaluate = Evaluate()
   
    #找到几步比较好的走步
    def search_several_good_nodes( self , player , board , numGoodNodes ):
        #记录goodNodeArray里边已经存了多少个
        countGood = 0
        tmpNode = Node()
        goodNodeArray = []
        for i in range( 0 , MAX_LINE ):
            for j in range( 0 , MAX_LINE ):
                if board[ i ][ j ] == EMPTY:
                    board[ i ][ j ] = player
                    tmpNode = self.evaluate.getValue( player , board )
                    board[ i ][ j ] = EMPTY
                    tmpNode.x = i
                    tmpNode.y = j
                   
                    countGood += 1
                    if countGood < = numGoodNodes:
                        goodNodeArray.append( tmpNode )
                        if( countGood == numGoodNodes ):
                            goodNodeArray = sorted( goodNodeArray , key = lambda node: -node.value )
                    else:
                        if tmpNode.value > goodNodeArray[ numGoodNodes - 1 ].value:
                            for k in range( numGoodNodes ):
                                if tmpNode.value > goodNodeArray[ k ].value:
                                    goodNodeArray[ k ] = tmpNode
                                    break  
        return goodNodeArray
    #alpha-beta减枝搜索算法  
    def alphaBetaSearch( self , search_depth , alpha , beta , player ):
        score = 0
        goodNodes = []
        badNodes = [ Node() ]
        goodNodes = self.search_several_good_nodes( player , self.chessBoard , self.numOfGoodNodes )
        badNodes = self.search_several_good_nodes( RIVAL if player == MYSELF else RIVAL , self.chessBoard , 1 )
        if goodNodes[ 0 ].win == WIN:
            if search_depth == 1:
                self.bestMove.x = goodNodes[ 0 ].x
                self.bestMove.y = goodNodes[ 0 ].y
                return goodNodes[ 0 ].value
        if badNodes[ 0 ].win == WIN:
            if search_depth == 1:
                self.bestMove.x = badNodes[ 0 ].x
                self.bestMove.y = badNodes[ 0 ].y
                return badNodes[ 0 ].value
        if search_depth == self.depth:
            return goodNodes[ 0 ].value if search_depth % 2 else -goodNodes[ 0 ].value
        for i in range( self.numOfGoodNodes ):
            self.chessBoard[ goodNodes[ i ].x ][ goodNodes[ i ].y ] = player
            score = -self.alphaBetaSearch( search_depth + 1 , -beta , -alpha , RIVAL if player == MYSELF else MYSELF )
            self.chessBoard[ goodNodes[ i ].x ][ goodNodes[ i ].y ] = EMPTY
            if score >= beta:
                return beta
            if score > alpha:
                alpha = score
                if search_depth == 1:
                    self.bestMove.x = goodNodes[ i ].x
                    self.bestMove.y = goodNodes[ i ].y
        return alpha

def test():
    chessBoard = [ [ EMPTY for i in range( MAX_LINE ) ] for j in range( MAX_LINE ) ]
    chessBoard[ 5 ][ 7 ] = chessBoard[ 6 ][ 7 ] = chessBoard[ 7 ][ 7 ] = MYSELF
    chessBoard[ 5 ][ 8 ] = chessBoard[ 6 ][ 8 ] = RIVAL
    #这里搜索深度和广度都为3,深度和广度越大,搜索时间越长,结果也越准确
    search = Search( 3 , 3 , chessBoard )
    for i in range( MAX_LINE ):
        print search.chessBoard[ i ]
    print 'it\'s my turn !'
    print 'calculating...'
    search.alphaBetaSearch( 1 , -INIT_MAX , INIT_MAX , RIVAL )
    print search.bestMove.x , search.bestMove.y
    chessBoard[ search.bestMove.x ][ search.bestMove.y ] = RIVAL
    for i in range( MAX_LINE ):
        print chessBoard[ i ]
    print 'it\'s your turn !'
    print 'calculating...'
    search = Search( 3 , 3 , chessBoard )
    search.alphaBetaSearch( 1 , -INIT_MAX , INIT_MAX , MYSELF )
    print search.bestMove.x , search.bestMove.y
    chessBoard[ search.bestMove.x ][ search.bestMove.y ] = MYSELF
    for i in range( MAX_LINE ):
        print chessBoard[ i ]
if __name__ == '__main__':
    test()

源码下载

引子–MediaRecorder引来的思考

Android中是提供录音这个API的,调用非常简单,MediaRecorder的文档给出了一个example,下面是我实现的一个servcie(用service是利于测试通话录音):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
package org.footoo.mediarecorder ;

import android.app.Service ;
import android.content.Intent ;
import android.media.MediaRecorder ;
import android.media.MediaRecorder.AudioSource ;
import android.media.MediaRecorder.OutputFormat ;
import android.os.IBinder ;

public class RecorderService extends Service
{
    MediaRecorder mediaRecorder ;
   
    @Override
    public IBinder onBind( Intent intent )
    {
        return null ;
    }
   
    @Override
    public void onCreate()
    {
        super.onCreate() ;
    }
   
    @Override
    public void onStart( Intent intent , int startId )
    {
        super.onStart( intent , startId ) ;
        mediaRecorder = new MediaRecorder() ;
        //∆ 这里设置录音源,关键在于这里
        mediaRecorder.setAudioSource( AudioSource.MIC ) ;
        // 设置输出格式
        mediaRecorder.setOutputFormat( OutputFormat.RAW_AMR ) ;
        mediaRecorder.setAudioEncoder( MediaRecorder.AudioEncoder.AMR_NB ) ;
        mediaRecorder.setOutputFile( "/sdcard/media.amediaRecorder" ) ;
        try
        {
            mediaRecorder.prepare() ;
            mediaRecorder.start() ;
        }
        catch( Exception e )
        {
        }
       
    }
   
    @Override
    public void onDestroy()
    {
        mediaRecorder.stop() ;
        mediaRecorder.release() ;
       
        super.onDestroy() ;
    }
}

也就是先设置一下录音源、录音格式等,然后调用prepare(),最后start()即可录音。MediaRecorder.stop()停止录音,MediaRecorder.release()释放资源,非常简单。

好了,重头戏来了。我们可以通过mediaRecorder.setAudioSource()设置录音源,在这里我们设置的是AudioSource.MIC。其他的录音源还有AudioSource.VOICE_CALL、AudioSource.VOICE_DOWNLINK、AudioSource.VOICE_UPLINK、AudioSource.VOICE_RECOGNITION、AudioSource.CAMCORDER、AudioSource.DEFAULT。让我们看看官方文档的解释吧:

其中最有嫌疑的是AudioSource.VOICE_CALL,uplink和downlink就是上行线和下行线,在卫星电信中,下行线就是从卫星下行到一个或者多个地面站或者接收器的线路,上行线就是从地面站链接到卫星的线路。那就在手上的Nexus S测试一下AudioSource.VOICE_CALL。运行程序开始录音,然后随便拨一个电话,比如说可怜的10086。然后停止录音,打开录制的音频,你会发现什么都没录到。这就怪了,为什么不好使呢?google了一下,网上说的是有的手机硬件不支持。到底是不是这样呢?毕竟网上说的没有什么可靠的依据,我们当执七分怀疑的态度。

那就让我们看一下Android源代码寻一下根究一下底吧,我们的对象是MediaRecorder.setAudioSource()方法。这里我用的版本是2.3.3。

其Frameworks Layer的源代码在frameworks/base/media/java/android/media/MediaRecorder.java,在该类的中的第一行有这么一段代码:

1
2
3
4
static{
    System.loadLibrary("media_jni");
    native_init();
}

看来该类是用了java的JNI(Java Native Interface)机制(我们会在后续的文章里介绍JNI机制),这样说来MediaRecorder.setAudioSource()肯定不会在这里实现,看一下MediaRecorder.setAudioSource(),果然。其是这样定义的,使用了navite关键字,表示在native层实现:

1
public native void setAudioSource(int audio_source) throws IllegalStateException;

那我们就来看一下JNI层是怎么实现setAudioSource()的,代码在frameworks/base/media/jni/android_media_MediaRecorder.cpp。

1
2
3
4
5
6
7
8
9
10
11
static void android_media_MediaRecorder_setAudioSource(JNIEnv *env, jobject thiz, jint as)
{
    LOGV("setAudioSource(%d)", as);
    if (as < AUDIO_SOURCE_DEFAULT || as >= AUDIO_SOURCE_LIST_END) {
        jniThrowException(env, "java/lang/IllegalArgumentException", "Invalid audio source");
        return;
    }

    sp<mediarecorder> mr = getMediaRecorder(env, thiz);
    process_media_recorder_call(env, mr->setAudioSource(as), "java/lang/RuntimeException", "setAudioSource failed.");
}</mediarecorder>

3个传入的参数涉及到JNI,在这里先不讲,我们只需将env理解成JNI环境,thiz为MediaRecorder对象,as为int类型(在这里为audio_source参数,即录音源)就可以了。if语句先判断as是否为已定义的录音源中的一个,如果不是,抛出异常。sp中的sp是什么东东?其实是strong pointer的意思,我们将其理解为指针就行。sp mr = getMediaRecorder(env, thiz),先得到MediaRecorder,然后调用native层的mr->setAudioSource(as) , process_media_recorder_call()是对其返回结果的错误处理。那么native层是怎么处理的呢?让我们看一下,代码在frameworks/base/media/libmedia/mediarecorder.cpp:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
status_t MediaRecorder::setAudioSource(int as)
{
    LOGV("setAudioSource(%d)", as);
    if(mMediaRecorder == NULL) {
        LOGE("media recorder is not initialized yet");
        return INVALID_OPERATION;
    }
    if (mCurrentState & MEDIA_RECORDER_IDLE) {
        LOGV("Call init() since the media recorder is not initialized yet");
        status_t ret = init();
        if (OK != ret) {
            return ret;
        }
    }
    if (mIsAudioSourceSet) {
        LOGE("audio source has already been set");
        return INVALID_OPERATION;
    }
    if (!(mCurrentState & MEDIA_RECORDER_INITIALIZED)) {
        LOGE("setAudioSource called in an invalid state(%d)", mCurrentState);
        return INVALID_OPERATION;
    }

    status_t ret = mMediaRecorder->setAudioSource(as);
    if (OK != ret) {
        LOGV("setAudioSource failed: %d", ret);
        mCurrentState = MEDIA_RECORDER_ERROR;
        return ret;
    }
    mIsAudioSourceSet = true;
    return ret;
}

其先经过一系列判断最终调用mMediaRecorder->setAudioSource(as),我们怎么没看到mMediaRecorder的定义?其是在frameworks/base/include/media/mediarecorder.h文件中定义的,是一个sp类型,怎么又出现了一个IMediaRecorder?这还真是一层套一层!那让我们看一下IMediaRecorder吧:
其类定义为:

1
2
class BpMediaRecorder: public BpInterface<imediarecorder>  
</imediarecorder>

原来是一个BpInterface,那么BpInterface又是什么?这个我们后面在讲。直接看setAudioSource()函数:

1
2
3
4
5
6
7
8
9
status_t setAudioSource(int as)
    {
        LOGV("setAudioSource(%d)", as);
        Parcel data, reply;
        data.writeInterfaceToken(IMediaRecorder::getInterfaceDescriptor());
        data.writeInt32(as);
        remote()->transact(SET_AUDIO_SOURCE, data, &reply);
        return reply.readInt32();
    }

Parcel我们可以简单的认为是一个存储数据的容器。首先将我们的重要参数封装到data里边,然后将remote()->transact()函数,这什么跟什么啊,怎么突然又冒出来一个
remote()->transact()?我们根据继承关系一步步找,终于在frameworks/base/include/binder/Binder.h种找到了remote()的定义,其返回类型为IBinder*。噢,终于涉及到了Android中十分重要的Binder机制了,但是我们在这里不讲Binder,放在后面讲。

继续,查看IBinder的transact函数,其定义为:

1
virtual status_t transact( uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags = 0) = 0;

原来是一个纯虚函数。根据Binder机制,其应该调用BpXXX,p代表proxy,远程服务在本地的代理的意思。那么调用的应该是BpBinder,看了一下frameworks/base/include/binder/BpBinder.h,果然继承IBinder。下面是BpBinder.cpp的transact()函数:

1
2
3
4
5
6
7
8
9
10
11
12
13
status_t BpBinder::transact(
    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
    // Once a binder has died, it will never come back to life.
    if (mAlive) {
        status_t status = IPCThreadState::self()->transact(
            mHandle, code, data, reply, flags);
        if (status == DEAD_OBJECT) mAlive = 0;
        return status;
    }

    return DEAD_OBJECT;
}

没完了是不是-_-!!又调用IPCThreadState::self()->transact(),晕了嘛?IPCThreadState是每一个线程都有,并且只有一个,使用了单例模式,处理有关线程的事务。让我们看一下IPCThreadState::self()->transact()函数,其在frameworks/base/libs/binder/IPCThreadState.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
status_t IPCThreadState::transact(int32_t handle,
                                  uint32_t code, const Parcel& data,
                                  Parcel* reply, uint32_t flags)
{
    status_t err = data.errorCheck();

    flags |= TF_ACCEPT_FDS;

    IF_LOG_TRANSACTIONS() {
        TextOutput::Bundle _b(alog);
        alog < < "BC_TRANSACTION thr " << (void*)pthread_self() << " / hand "
            << handle << " / code " << TypeCode(code) << ": "
            << indent << data << dedent << endl;
    }
   
    if (err == NO_ERROR) {
        LOG_ONEWAY(">>>> SEND from pid %d uid %d %s", getpid(), getuid(),
            (flags & TF_ONE_WAY) == 0 ? "READ REPLY" : "ONE WAY");
        err = writeTransactionData(BC_TRANSACTION, flags, handle, code, data, NULL);
    }
   
    if (err != NO_ERROR) {
        if (reply) reply->setError(err);
        return (mLastError = err);
    }
   
    if ((flags & TF_ONE_WAY) == 0) {
        #if 0
        if (code == 4) { // relayout
            LOGI(">>>>>> CALLING transaction 4");
        } else {
            LOGI(">>>>>> CALLING transaction %d", code);
        }
        #endif
        if (reply) {
            err = waitForResponse(reply);
        } else {
            Parcel fakeReply;
            err = waitForResponse(&fakeReply);
        }
        #if 0
        if (code == 4) { // relayout
            LOGI("< <<<<< RETURNING transaction 4");
        } else {
            LOGI("<<<<<< RETURNING transaction %d", code);
        }
        #endif
       
        IF_LOG_TRANSACTIONS() {
            TextOutput::Bundle _b(alog);
            alog << "BR_REPLY thr " << (void*)pthread_self() << " / hand "
                << handle << ": ";
            if (reply) alog << indent << *reply << dedent << endl;
            else alog << "(none requested)" << endl;
        }
    } else {
        err = waitForResponse(NULL, NULL);
    }
   
    return err;
}

通过一系列的判断最终调用了writeTransactionData()函数,然后waitForResponse()等待返回结果。看一下writeTransactionData()函数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
status_t IPCThreadState::writeTransactionData(int32_t cmd, uint32_t binderFlags,
    int32_t handle, uint32_t code, const Parcel& data, status_t* statusBuffer)
{
    binder_transaction_data tr;

    tr.target.handle = handle;
    tr.code = code;
    tr.flags = binderFlags;
   
    const status_t err = data.errorCheck();
    if (err == NO_ERROR) {
        tr.data_size = data.ipcDataSize();
        tr.data.ptr.buffer = data.ipcData();
        tr.offsets_size = data.ipcObjectsCount()*sizeof(size_t);
        tr.data.ptr.offsets = data.ipcObjects();
    } else if (statusBuffer) {
        tr.flags |= TF_STATUS_CODE;
        *statusBuffer = err;
        tr.data_size = sizeof(status_t);
        tr.data.ptr.buffer = statusBuffer;
        tr.offsets_size = 0;
        tr.data.ptr.offsets = NULL;
    } else {
        return (mLastError = err);
    }
   
    mOut.writeInt32(cmd);
    mOut.write(&tr, sizeof(tr));
   
    return NO_ERROR;
}

其主要是将要处理的数据封装了一下,传到了mOut上,等待被处理。那么waitForResponse()函数做了什么工作呢?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
status_t IPCThreadState::waitForResponse(Parcel *reply, status_t *acquireResult)
{
    int32_t cmd;
    int32_t err;

    while (1) {
        if ((err=talkWithDriver()) < NO_ERROR) break;
        err = mIn.errorCheck();
        if (err < NO_ERROR) break;
        if (mIn.dataAvail() == 0) continue;
       
        cmd = mIn.readInt32();
       
        IF_LOG_COMMANDS() {
            alog << "Processing waitForResponse Command: "
                << getReturnString(cmd) << endl;
        }

        switch (cmd) {
        case BR_TRANSACTION_COMPLETE:
            if (!reply && !acquireResult) goto finish;
            break;
       
        case BR_DEAD_REPLY:
            err = DEAD_OBJECT;
            goto finish;

        case BR_FAILED_REPLY:
            err = FAILED_TRANSACTION;
            goto finish;
       
        case BR_ACQUIRE_RESULT:
            {
                LOG_ASSERT(acquireResult != NULL, "Unexpected brACQUIRE_RESULT");
                const int32_t result = mIn.readInt32();
                if (!acquireResult) continue;
                *acquireResult = result ? NO_ERROR : INVALID_OPERATION;
            }
            goto finish;
       
        case BR_REPLY:
            {
                binder_transaction_data tr;
                err = mIn.read(&tr, sizeof(tr));
                LOG_ASSERT(err == NO_ERROR, "Not enough command data for brREPLY");
                if (err != NO_ERROR) goto finish;

                if (reply) {
                    if ((tr.flags & TF_STATUS_CODE) == 0) {
                        reply->ipcSetDataReference(
                            reinterpret_cast<const uint8_t*>(tr.data.ptr.buffer),
                            tr.data_size,
                            reinterpret_cast</const><const size_t*>(tr.data.ptr.offsets),
                            tr.offsets_size/sizeof(size_t),
                            freeBuffer, this);
                    } else {
                        err = *static_cast</const><const status_t*>(tr.data.ptr.buffer);
                        freeBuffer(NULL,
                            reinterpret_cast</const><const uint8_t*>(tr.data.ptr.buffer),
                            tr.data_size,
                            reinterpret_cast</const><const size_t*>(tr.data.ptr.offsets),
                            tr.offsets_size/sizeof(size_t), this);
                    }
                } else {
                    freeBuffer(NULL,
                        reinterpret_cast</const><const uint8_t*>(tr.data.ptr.buffer),
                        tr.data_size,
                        reinterpret_cast</const><const size_t*>(tr.data.ptr.offsets),
                        tr.offsets_size/sizeof(size_t), this);
                    continue;
                }
            }
            goto finish;

        default:
            err = executeCommand(cmd);
            if (err != NO_ERROR) goto finish;
            break;
        }
    }

finish:
    if (err != NO_ERROR) {
        if (acquireResult) *acquireResult = err;
        if (reply) reply->setError(err);
        mLastError = err;
    }
   
    return err;
}
</const>

其首先调用talkWithDriver()函数来执行相应的命令,然后将返回结果存储到mIn,读出mIn里的cmd,然后进行处理。talkWithDriver()函数似乎就是关键点了,那么talkWithDriver()到底做了什么呢?我们来看一下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
status_t IPCThreadState::talkWithDriver(bool doReceive)
{
    LOG_ASSERT(mProcess->mDriverFD >= 0, "Binder driver is not opened");
   
    binder_write_read bwr;
   
    // Is the read buffer empty?
    const bool needRead = mIn.dataPosition() >= mIn.dataSize();
   
    // We don't want to write anything if we are still reading
    // from data left in the input buffer and the caller
    // has requested to read the next data.
    const size_t outAvail = (!doReceive || needRead) ? mOut.dataSize() : 0;
   
    bwr.write_size = outAvail;
    bwr.write_buffer = (long unsigned int)mOut.data();

    // This is what we'll read.
    if (doReceive && needRead) {
        bwr.read_size = mIn.dataCapacity();
        bwr.read_buffer = (long unsigned int)mIn.data();
    } else {
        bwr.read_size = 0;
    }
   
    IF_LOG_COMMANDS() {
        TextOutput::Bundle _b(alog);
        if (outAvail != 0) {
            alog < < "Sending commands to driver: " << indent;
            const void* cmds = (const void*)bwr.write_buffer;
            const void* end = ((const uint8_t*)cmds)+bwr.write_size;
            alog << HexDump(cmds, bwr.write_size) << endl;
            while (cmds < end) cmds = printCommand(alog, cmds);
            alog << dedent;
        }
        alog << "Size of receive buffer: " << bwr.read_size
            << ", needRead: " << needRead << ", doReceive: " << doReceive << endl;
    }
   
    // Return immediately if there is nothing to do.
    if ((bwr.write_size == 0) && (bwr.read_size == 0)) return NO_ERROR;
   
    bwr.write_consumed = 0;
    bwr.read_consumed = 0;
    status_t err;
    do {
        IF_LOG_COMMANDS() {
            alog << "About to read/write, write size = " << mOut.dataSize() << endl;
        }
#if defined(HAVE_ANDROID_OS)
        if (ioctl(mProcess->mDriverFD, BINDER_WRITE_READ, &bwr) >= 0)
            err = NO_ERROR;
        else
            err = -errno;
#else
        err = INVALID_OPERATION;
#endif
        IF_LOG_COMMANDS() {
            alog < < "Finished read/write, write size = " << mOut.dataSize() << endl;
        }
    } while (err == -EINTR);
   
    IF_LOG_COMMANDS() {
        alog << "Our err: " << (void*)err << ", write consumed: "
            << bwr.write_consumed << " (of " << mOut.dataSize()
            << "), read consumed: " << bwr.read_consumed << endl;
    }

    if (err >= NO_ERROR) {
        if (bwr.write_consumed > 0) {
            if (bwr.write_consumed < (ssize_t)mOut.dataSize())
                mOut.remove(0, bwr.write_consumed);
            else
                mOut.setDataSize(0);
        }
        if (bwr.read_consumed > 0) {
            mIn.setDataSize(bwr.read_consumed);
            mIn.setDataPosition(0);
        }
        IF_LOG_COMMANDS() {
            TextOutput::Bundle _b(alog);
            alog < < "Remaining data size: " << mOut.dataSize() << endl;
            alog << "Received commands from driver: " << indent;
            const void* cmds = mIn.data();
            const void* end = mIn.data() + mIn.dataSize();
            alog << HexDump(cmds, mIn.dataSize()) << endl;
            while (cmds < end) cmds = printReturnCommand(alog, cmds);
            alog << dedent;
        }
        return NO_ERROR;
    }
   
    return err;
}

通过一系列的封装判断,最终调用ioctl(mProcess->mDriverFD, BINDER_WRITE_READ, &bwr)函数,然后将结果存储在mIn里。噢,看到ioctl函数后,你是不是恍然大悟了呢?尼玛,千呼万唤始出来啊!剩下的就不多说了吧。

项目简介

平时不时听到有人抱怨Android系统各种缺陷,比如不支持关机闹铃,不支持通话录音,不能删除多用户(这个4.0中好像已经修复)。不支持关机闹铃是由于底层无硬件支持,因此即使修改系统也不能真正的实现该功能,但是理论上来说可以实现伪关机,从而实现伪关机闹铃。

通话录音也是一个需求比较大的功能,Android系统也有实现MediaRecorder,支持录音源Mic、Call等,但是有的机型从录音源Call中录音好使,有的机型却不好使,比较诡异。

本项目主要通过分析修改Android底层源代码,从而实现通话录音。而此系列文章主要记录分析做每一步的思路,以供后来者参考以及备忘。

项目地址:https://github.com/Yan66/AndroidCallRecorder

Android source compiling On Mac OS

就将这周在Mac OS下编译android source的蛋疼经历简单记一下吧,虽然问题还没解决==!。

OS : 最新版本10.7.3(Lion)
Xcode Version: 4.3.2
Android source: 2.3.3

本以为按照官方的教程做了就会好使,事实证明我太天真了。

官网上有句话是这样说的:

我的Xcode版本不幸中枪,试了一下果然不好使。其提示说:
Please install the 10.5 SDK on this machine at /Developer/SDKs/MacOSX10.5.sdk

于是开始google,在CSDN上找到这篇文章,于是注册Developer ID,到官网上下载(顺便吐槽一下,官网速度慢的跟狗屎一样,4个多G,用了5,6个小时)了一个3.2.6版本的。心想这下应该好使了吧,于是愉快的按照该贴设置了一下。“make -j8”提示:

group上又找到了这么一个帖子,跟上篇文章大体思路一样。有个人说是编译器的问题,说是3.2.6貌似也不好使,于是又到官网上把3.2.4下下来了(又是4个多G),编译一下,果然也不好使,但是提示的错误变了:

搜索该问题无果后,重新看了一下官网教程,发现说“We recommend version 3.1.4 or newer”,难道3.1.4好使?于是抱着乱投医的态度下载了下来(尼玛太坑爹了。。),同样不好使。

又仔细看了下group上的那个贴子,发现有一个地方说是要把CC变量给改成3.2.x的gcc,于是一个一个试了一下,各种export后,悲剧的发现,又被坑了。漫长的等待已使我彻底恶心了,花费了整整两天的时间。

与其一头栽在这个拉不出屎的茅坑,不如换个系统吧。因为Mac是unix-like的,装个ubuntu双系统不值得,又考虑到8G还算海量的内存,果断VM。至于mac下各种编译不出来的问题,放到以后慢慢解决,毕竟不能因为这个耽误进度。有时间下个4.x的版本试试。

过程中发生一个有趣的事:
我把原先安装的Xcode4.3.2卸载后,/Developer文件夹完全删除,然后”locate uninstall-devtools”,其输出在/Developer/Library/uninstall-devtools,这就奇怪了。我不是删了吗?于是果断“爷们”了locate一下,发现

于是明白怎么回事了,原来当你执行locate命令的时候,其查找的是已经保存在数据库中的对文件路径的归档,而不是真正意义上的重新遍历整个目录。执行“/usr/libexec/locate.updatedb”更新数据库后再查询即可。

嵌入式实验5-QT计算器

首先,祝某学姐生日快乐,永远漂亮可爱。

然后就是此代码仅供参考,虽然public,但是希望尽量还是自己思考,那样才能学到更多东西。

在源代码上修改还是非常简单的,过程中竟然发现源代码中有几处竟然几乎是多余的,也不知道老师从哪得到的原代码。需要改动的代码有calculator.h和calculator.cpp。

calculator.h:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
/*
 *author: shiyanhui
 *date:   2012/3/25
 */

#ifndef CALCULATOR_H
#define CALCULATOR_H

#include <qdialog>

QT_BEGIN_NAMESPACE
class QLineEdit;
QT_END_NAMESPACE
class Button;
class QTextCodec ;

class Calculator : public QDialog
{
    Q_OBJECT

public:
    Calculator(QWidget *parent = 0);

private slots:
    void digitClicked();
    void unaryOperatorClicked();
    void additiveOperatorClicked();
    void multiplicativeOperatorClicked();
    void equalClicked();
    void pointClicked();
    void changeSignClicked();
    void backspaceClicked();
    void clear();
    void clearAll();
    void clearMemory();
    void readMemory();
    void setMemory();
    void addToMemory();
    void _UnaryOperation() ;
    void _BinaryOperarion() ;
private:
    Button *createButton(const QString &text, const char *member);
    void abortOperation();
    bool calculate(double rightOperand, const QString &pendingOperator);

    double sumInMemory;
    double sumSoFar;
    double factorSoFar;
    QString pendingAdditiveOperator;
    QString pendingMultiplicativeOperator;
    QString pendingOperator ;
    bool waitingForOperand;

    QLineEdit *display;
    enum { NumDigitButtons = 10 };
    Button *digitButtons[NumDigitButtons];
};

#endif
</qdialog>

calculator.cpp:
Continue reading

神器vim之再回顾

自从成为“牛逼哄哄”的mac用户后,vim也没怎么配置。由于软III,需要阅读android源代码,于是今天又将vim重新配置了一下。虽然在mac os下有GUI版的vim——MacVim,但是个人始终感觉MacVim不如在终端下的爽。先截个图,赤果果的炫一下。。

1、标签:ctags+taglist
taglist能够把一个文件中的函数名或者是变量生成一个标签list,从而有助于定位函数和变量,有助于理解代码。个人感觉为vim必装插件。

taglist只支持Exuberant Ctags,但是mac os下的ctags不是Exuberant Ctags,因此必须先装上Exuberant Ctags。然后在.vimrc中写明路径:let Tlist_Ctags_Cmd = “/path/ctags”。Exuberant Ctags默认的安装路径是/usr/local/bin/ctags,因此只要写let Tlist_Ctags_Cmd = “/usr/local/bin/ctags”即可。

2、目录树:NERDTree
浏览源代码时还有一个需求就是目录树,这样能够增加阅读效率。在此下载,然后将解压后的目录下的文件copy到~/.vim中相对应的目录文件下就行了。

3、自动补齐:neocomplcache
此插件个人一直在用,因为其速度很快,支持多种语言,非常强大,能够极大的提高敲代码的效率,因此极力推荐。在此下载

4、键盘映射
这个看个人喜好,我喜欢将F1映射为:NERDTreeToggle,而将F2映射为:TlistToggle。

最后将.vimrc文件贴下,以便以后换系统重装。
Continue reading

嵌入式实验4之计算器

忽然想起了意林的名言:作业开源才是大势所趋。汗。。

做完后把代码copy到了U盘里,结果不知怎么的落在那了。某学姐不给力,也没找到。于是又重改了一遍,应该没错,除了可能某个地方代码敲错。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
/*
 *author: shiyanhui
 *date:   2012/3/21
 */

#include "config.h"

#include <stdio .h>
#include <stdlib .h>
#include <string .h>
#include <signal .h>
#include <sys /fcntl.h>
#include </sys><sys /ioctl.h>
#include </sys><sys /mman.h>
#include </sys><sys /time.h>
#include <memory .h>

#include "tslib.h"
#include "fbutils.h"

static int palette[] = { 0x000000 , 0xffe080 , 0xffffff , 0xe0c0a0 , 0x304050 ,
        0x80b8c0 } ;
static char* button_text[ 15 ] = { "0" , "1" , "2" , "3" , "4" , "5" , "6" , "7" , "8" , "9" , "+" , "-" , "*" , "/" , "=" } ;

#define NR_COLORS (sizeof (palette) / sizeof (palette [0]))

//the space between two buttons
#define BUTTON_SPACING 20

//the width and height of button
#define BUTTON_W_H 40

struct ts_button
{
    int x , y , w , h ;
    char *text ;
    int flags ;
#define BUTTON_ACTIVE 0x00000001
} ;

struct num
{
    char number[ 20 ] ;
    int index ;
} ;

/* [inactive] border fill text [active] border fill text */
static int button_palette[6] = { 1 , 4 , 2 , 1 , 5 , 0 } ;

#define NR_BUTTONS 16
static struct ts_button buttons[NR_BUTTONS] ;

//expression we should handle
static char* expression ;

//the final expression result
static char* expression_result ;

static void sig( int sig )
{
    close_framebuffer() ;
    fflush( stderr ) ;
    printf( "signal %d caught\n" , sig ) ;
    fflush( stdout ) ;
    exit( 1 ) ;
}

//join two strings
static char* join( char* a , char* b )
{
      static char* result;
      int len = strlen( a ) + strlen( b ) + 1 ;
      result = ( char* )malloc( len * sizeof( char ) ) ;
      memset( result , 0 , len * sizeof( char ) ) ;
      strcpy( result , a ) ;
      strcat( result , b ) ;
      return result;
}

//convert int to string
static char* num2string( int num )
{
    static char result[10] ;
    char tmp[10] ;
    int index = -1 ;
    int remainder ;
    int i ;
    while( 1 )
    {
        remainder = num % 10 ;
        tmp[ ++ index] = ( char ) ( '0' + remainder ) ;
        num /= 10 ;
        if( !num )
            break ;
    }
    for( i = 0 ; i < = index ; ++ i )
    {
        result[i] = tmp[index - i] ;
    }
    return result ;
}

static void button_draw( struct ts_button *button )
{
    int s = ( button->flags & BUTTON_ACTIVE ) ? 3 : 0 ;
    rect( button->x , button->y , button->x + button->w - 1 ,
            button->y + button->h - 1 , button_palette[s] ) ;
    fillrect( button->x + 1 , button->y + 1 , button->x + button->w - 2 ,
            button->y + button->h - 2 , button_palette[s + 1] ) ;
    put_string_center( button->x + button->w / 2 , button->y + button->h / 2 ,
            button->text , button_palette[s + 2] ) ;
}

//calculate the simple expression, like "3+11"、"8*7" etc.
static void calculate()
{
    int i ;
    //calculate mode: 1 plus, 2 minus, 3 multiply, 4 devide
    int mode = -1 ;
    int symbol_index = -1 ;
    int find = 0 ;

    struct num a , b ;
    a.index = -1 ;
    b.index = -1 ;

    for( i = 0 ; i < strlen( expression ) ; ++ i )
    {
        if( expression[ i ] == '+' )
        {
            symbol_index = i ;
            mode = 1 ;
            find = 1 ;
        }
        else if( expression[ i ] == '-' )
        {
            symbol_index = i ;
            mode = 2 ;
            find = 1 ;
        }
        else if( expression[ i ] == '*' )
        {
            symbol_index = i ;
            mode = 3 ;
            find = 1 ;
        }
        else if( expression[ i ] == '/' )
        {
            symbol_index == i ;
            mode = 4 ;
            find = 1 ;
        }
        else
        {
            if( find )
            {
                b.number[ ++ b.index ] = expression[ i ] ;
            }
            else
            {
                a.number[ ++ a.index ] = expression[ i ] ;
            }
        }
    }

    if( !find )
    {
        expression_result = "NOT SUPPORT" ;
        return ;
    }

    int _a = atoi( a.number ) ;
    int _b = atoi( b.number ) ;
   
    switch( mode )
    {
    case 1:
        expression_result = num2string( _a + _b ) ;
        break ;
    case 2:
        expression_result = num2string( _a - _b ) ;
        break ;
    case 3:
        expression_result = num2string( _a * _b ) ;
        break ;
    case 4:
        expression_result = num2string( _a / _b ) ;
    }
}

//handle the pressed event
static void button_handle( struct ts_sample *samp )
{
    int i ;
    for( i = 0 ; i < NR_BUTTONS - 1 ; ++ i )
    {
        int inside = ( samp->x >= buttons[i].x ) && ( samp->y >= buttons[i].y )
                && ( samp->x < buttons[i].x + buttons[i].w )
                && ( samp->y < buttons[i].y + buttons[i].h ) ;
        if( samp->pressure > 0 )
        {
            if( inside )
            {
                if( !( buttons[i].flags & BUTTON_ACTIVE ) )
                {
                    buttons[i].flags |= BUTTON_ACTIVE ;
                    button_draw( &buttons[i] ) ;
                }
            }
            else if( buttons[i].flags & BUTTON_ACTIVE )
            {
                buttons[i].flags &= ~BUTTON_ACTIVE ;
                button_draw( &buttons[i] ) ;
            }
        }
        else if( buttons[i].flags & BUTTON_ACTIVE )
        {
            buttons[i].flags &= ~BUTTON_ACTIVE ;
            button_draw( &buttons[i] ) ;
            if( i < NR_BUTTONS - 2 )
            {
                if( expression != NULL )
                {
                    char* tmp = expression ;
                    expression = join( tmp , button_text[i] ) ;
                    free( tmp ) ;
                }
                else
                {
                    expression = join( "" , button_text[i] ) ;
                }
                buttons[15].text = expression ;
            }
            else
            {
                calculate() ;
                buttons[15].text = expression_result ;
                expression = NULL ;
            }
        }
    }
}


static void refresh_screen()
{
    int i ;

    fillrect( 0 , 0 , xres - 1 , yres - 1 , 0 ) ;

    for( i = 0 ; i < NR_BUTTONS ; i ++ )
        button_draw( &buttons[i] ) ;
}

int main()
{
    struct tsdev *ts ;
    unsigned int i , j ;
    char *tsdevice = NULL ;
   
    expression = NULL ;
   
    signal( SIGSEGV , sig ) ;
    signal( SIGINT , sig ) ;
    signal( SIGTERM , sig ) ;

    if( ( tsdevice = getenv( "TSLIB_TSDEVICE" ) ) == NULL )
    {
#ifdef USE_INPUT_API
        tsdevice = strdup ("/dev/input/event0") ;
#else
        tsdevice = strdup( "/dev/touchscreen/ucb1x00" ) ;
#endif /* USE_INPUT_API */
    }

    ts = ts_open( tsdevice , 0 ) ;

    if( !ts )
    {
        perror( tsdevice ) ;
        exit( 1 ) ;
    }

    if( ts_config( ts ) )
    {
        perror( "ts_config" ) ;
        exit( 1 ) ;
    }

    if( open_framebuffer() )
    {
        close_framebuffer() ;
        exit( 1 ) ;
    }

    for( i = 0 ; i < NR_COLORS ; i ++ )
        setcolor( i , palette[i] ) ;

    /* Initialize buttons */
    memset( &buttons , 0 , sizeof( buttons ) ) ;
    for( i = 0 ; i < 5 ; ++ i )
    {
        for( j = 0 ; j < 3 ; ++ j )
        {
            int index ;
            index = i * 3 + j ;
            buttons[ index ].w = BUTTON_W_H ;
            buttons[ index ].h = BUTTON_W_H ;
            buttons[ index ].x = ( j + 1 ) * BUTTON_SPACING + j * BUTTON_W_H ;
            buttons[ index ].y = ( i + 1 ) * BUTTON_SPACING + i * BUTTON_W_H ;
            buttons[ index ].text = button_text[ index ] ;
        }
    }
   
    buttons[ 15 ].w = BUTTON_W_H * 2 ;
    buttons[ 15 ].h = BUTTON_W_H * 2 ;
    buttons[ 15 ].x = 300 ;
    buttons[ 15 ].y = 100 ;
    buttons[ 15 ].text = "0" ;

    refresh_screen() ;
   
    while( 1 )
    {
        struct ts_sample samp ;
        int ret ;

        ret = ts_read( ts , &samp , 1 ) ;

        if( ret < 0 )
        {
            perror( "ts_read" ) ;
            close_framebuffer() ;
            exit( 1 ) ;
        }

        if( ret != 1 )
            continue ;

        //handle the pressed button
        button_handle( &samp ) ;
        refresh_screen() ;
    }
    close_framebuffer() ;
}

下载源码

找出包含某字符串的文件的路径—-find.py

该脚本实现了找出包含某一pattern的所有文件的路径。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#coding=utf-8
#author: Yan

import sys
import re
import os
import os.path

def find( path ):
    if os.path.isfile( path ):
        file = open( path )
        file_content = file.read()
        result = re.search( pattern , file_content )
        if result is not None:
            print path
        file.close()
        return
    for item in os.listdir( path ):
        find( path + '/' + item )
       
if len( sys.argv ) < 3:
    print 'Usage: find.py [pattern] [path]'
    exit()

pattern = re.compile( str( sys.argv[ 1 ] ) )
base_path = str( sys.argv[ 2 ] )

find( base_path )

Download here.

funf–with impress.js

impress.js相信很多前端开发人员已经早有耳闻了吧,其用js配合html5和css3实现了很多绚丽的效果。最近研究funf,于是就用impress.js做了一个关于funf的PPT,以观效果。wow,god! good!

注意:用箭头键控制播放,建议全屏.