安装jdk1.7.0_04后,同时设置环境变量,并且source。可是java -version查看后,还是只能查看到jdk1.6和jdk1.5一共两个版本,这两个版本都是fedora自带的。
解决方法:
#: alternatives --install /usr/bin/java java /usr/local/android/jdk1.7.0_04/bin/java 500
注意;/usr/local/android/jdk1.7.0_04/ 是我的jdk安装路径。
然后:
alternatives --config java
会出现三个选项,选择你刚才安装的1.7的jdk就可以了。
slab分配器 - 实例用法
其原理此处不再赘述,请参看:http://www.ibm.com/developerworks/cn/linux/l-linux-slab-allocator/
1. 定义一个 kmem_cache 对象,然后对其进行初始化
static struct kmem_cache *sample_cachep;
static void init_sample_cachep( void )
{
sample_cachep = kmem_cache_create(
"sample_cachep", /* Name */
32, /* Object Size */
0, /* Alignment */
SLAB_HWCACHE_ALIGN, /* Flags */
NULL); /* Constructor */
return;
}
这里是采用的通用slab缓存方式实现,这个特定的缓存包含 32 字节的对象,并且是硬件缓存对齐的(由标志参数 SLAB_HWCACHE_ALIGN 定义)。
如果采用专用slab缓存,那么必须要知道建立缓存对象的大小,比如,我们需要为sample_struct结构体建立一个专用的slab缓存,那么其调用格式如下:
static struct kmem_cache *sample_struct_cachep;
static void init_sample_struct_cache( void )
{
sample_struct_cachep = kmem_cache_create(
"sample_struct_cachep", /* Name */
sizeof(struct sample_struct), /* Object Size */
0, /* Alignment */
SLAB_HWCACHE_ALIGN, /* Flags */
NULL); /* Constructor */
return;
}
接下来以专用slab缓存为实例
2. 使用所分配的 slab 缓存对象,或释放所分配的 slab 缓存对象
int slab_test( void )
{
struct sample_struct *object;
printk( "Cache name is %s/n", kmem_cache_name( sample_struct_cachep ) );
printk( "Cache object size is %d/n", kmem_cache_size( sample_struct_cachep ) );
object = kmem_cache_alloc(sample_struct_cachep, GFP_KERNEL);
if (object) {
kmem_cache_free(sample_struct_cachep, object);
}
return 0;
}
3. slab 缓存的销毁。调用者必须确保在执行销毁操作过程中,不要从缓存中分配对象。
static void remove_sample_struct_cache( void )
{
if (sample_struct_cachep)
kmem_cache_destroy( sample_struct_cachep );
return;
}
4.所在slab缓存使用过程中,可以通过slabtop查看。
5. 实例
/**********************************************
* Author: lewiyon@hotmail.com
* File name: slabmod.c
* Description: slab缓存使用实例
* Date: 2012-07-26
*********************************************/
#include <linux/init.h>
#include <linux/module.h>
#include <linux/module.h>
#include <linux/unistd.h>
//#include <sys/type.h>
#include <linux/slab.h>
MODULE_LICENSE("GPL");
#define first 1000 /* 第一次尝试分配1000个对象 */
struct sample_struct {
int id;
char name[20];
char address[50];
};
static struct kmem_cache *sample_struct_cachep;
static struct sample_struct *sample1[first];
static int sample_mod_init(void)
{
int i;
sample_struct_cachep = kmem_cache_create(
"sample_struct_cachep", /* Name */
sizeof(struct sample_struct), /* Object Size */
0, /* Alignment */
SLAB_HWCACHE_ALIGN, /* Flags */
NULL); /* Constructor */
/* 确保创建成功:有可能失败 */
if (NULL == sample_struct_cachep)
return 1;
printk(KERN_INFO "Cache name is %s\n",
kmem_cache_name(sample_struct_cachep));
/* 首次分配 */
for (i = 0; i < first; i++)
{
sample1[i] = kmem_cache_alloc(sample_struct_cachep, GFP_KERNEL);
if (NULL == sample1[i])
{
int ii;
printk("First alloc ERR: %d/n", i);
for (ii = 0; ii < i; ii++)
{
kmem_cache_free(sample_struct_cachep, sample1[ii]);
sample1[ii] = NULL;
}
}
}
return 0;
}
static void sample_mod_exit(void)
{
int i;
if (sample1[0])
{
for (i = 0; i < first; i++)
{
kmem_cache_free(sample_struct_cachep, sample1[i]);
sample1[i] = NULL;
}
}
if (sample_struct_cachep)
{
kmem_cache_destroy( sample_struct_cachep );
printk(KERN_INFO "Destroy sample_struct_cachep!\n");
}
return ;
}
module_init(sample_mod_init);
module_exit(sample_mod_exit);
MODULE_AUTHOR("lewiyon@hotmail.com");
MODULE_DESCRIPTION("A Simple slab sample");
插入模块、删除模块前后slabtop观察结果
[root@RedHat ~]# slabtop -o | egrep "OBJS|sample_struct_cachep"
OBJS ACTIVE USE OBJ SIZE SLABS OBJ/SLAB CACHE SIZE NAME
[root@RedHat ~]# slabtop -o | egrep "OBJS|sample_struct_cachep"
OBJS ACTIVE USE OBJ SIZE SLABS OBJ/SLAB CACHE SIZE NAME
1020 1020 100% 0.12K 34 30 136K sample_struct_cachep
[root@RedHat ~]# slabtop -o | egrep "OBJS|sample_struct_cachep"
OBJS ACTIVE USE OBJ SIZE SLABS OBJ/SLAB CACHE SIZE NAME
1020 1010 99% 0.12K 34 30 136K sample_struct_cachep
[root@RedHat ~]# slabtop -o | egrep "OBJS|sample_struct_cachep"
OBJS ACTIVE USE OBJ SIZE SLABS OBJ/SLAB CACHE SIZE NAME
1020 1002 98% 0.12K 34 30 136K sample_struct_cachep
[root@RedHat ~]# slabtop -o | egrep "OBJS|sample_struct_cachep"
OBJS ACTIVE USE OBJ SIZE SLABS OBJ/SLAB CACHE SIZE NAME
1020 1001 98% 0.12K 34 30 136K sample_struct_cachep
[root@RedHat ~]# slabtop -o | egrep "OBJS|sample_struct_cachep"
OBJS ACTIVE USE OBJ SIZE SLABS OBJ/SLAB CACHE SIZE NAME
1020 1000 98% 0.12K 34 30 136K sample_struct_cachep
[root@RedHat ~]# slabtop -o | egrep "OBJS|sample_struct_cachep"
OBJS ACTIVE USE OBJ SIZE SLABS OBJ/SLAB CACHE SIZE NAME
1020 1000 98% 0.12K 34 30 136K sample_struct_cachep
[root@RedHat ~]# slabtop -o | egrep "OBJS|sample_struct_cachep"
OBJS ACTIVE USE OBJ SIZE SLABS OBJ/SLAB CACHE SIZE NAME
1020 1000 98% 0.12K 34 30 136K sample_struct_cachep
[root@RedHat ~]# slabtop -o | egrep "OBJS|sample_struct_cachep"
OBJS ACTIVE USE OBJ SIZE SLABS OBJ/SLAB CACHE SIZE NAME
1020 1000 98% 0.12K 34 30 136K sample_struct_cachep
[root@RedHat ~]# slabtop -o | egrep "OBJS|sample_struct_cachep"
OBJS ACTIVE USE OBJ SIZE SLABS OBJ/SLAB CACHE SIZE NAME
1020 1000 98% 0.12K 34 30 136K sample_struct_cachep
[root@RedHat ~]# slabtop -o | egrep "OBJS|sample_struct_cachep"
OBJS ACTIVE USE OBJ SIZE SLABS OBJ/SLAB CACHE SIZE NAME
[root@RedHat ~]# slabtop -o | egrep "OBJS|sample_struct_cachep"
OBJS ACTIVE USE OBJ SIZE SLABS OBJ/SLAB CACHE SIZE NAME
[root@RedHat ~]#
分析:
a. 再没有插入模块时,没有数据
b. 插入模块时,新建slab,这是数据都是active的,此时对象数目为OBJS = SLABS * OBJ/SLAB = 34*30 = 1020;
c. 随着模块稳定下来, 未使用的对象变为inactive,那么active数目就变味了1000;(与程序相对应)
d. 删除模块后,数据消失
com.android.mms.ui.ComposeMessageActivity com.android.mms.data.WorkingMessage com.android.mms.transaction.MessageSender com.android.mms.transaction.SmsMessageSender com.android.mms.transaction.SmsSingleRecipientSender com.android.mms.transaction.SmsReceiverService com.android.mms.transaction.SmsReceiver
该类是我们编辑短信的UI,与用户交互,如下图所示
当用户编辑完成,即可点击发送的按钮,将短信内容发送出去,点击sendbutton就会触发该button对应的监听器,由于ComposeMessageActivity实现了OnClickListener接口,所以最终调用到了onclick方法里。
1)onClick分析
该方法做了两件件事情:
一是调用isPreparedForSending方法判断当前短信是否准备发送,依据就是短信短信的接收者是否超过允许的上限,是否有接收者,以及短信是否有内容或者附件、主题之类的,不允许用户发送一条什么都没有的短信出去。
二是,上面的检查通过调用confirmSendMessageIfNeeded方法开始发送流程。当然并不是调用了该方法就一定能发送成功,该方法同样会做一系列的检查,直到符合要求了才会放行。
2)confirmSendMessageIfNeeded分析
该方法的逻辑调用如下图所示:
该方法会调用queueMessage()方法把处理发送的任务抛出去。
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(mContext);
boolean requestDeliveryReport = prefs.getBoolean(
MessagingPreferenceActivity.SMS_DELIVERY_REPORT_MODE,
DEFAULT_DELIVERY_REPORT_MODE);
for (int i = 0; i < mNumberOfDests; i++) {
try {
log("updating Database with sub = " + mSubscription);
Sms.addMessageToUri(mContext.getContentResolver(),
Uri.parse("content://sms/queued"), mDests[i],
mMessageText, null, mTimestamp,
true /* read */,
requestDeliveryReport,
mThreadId, mSubscription);
} catch (SQLiteException e) {
SqliteWrapper.checkSQLiteException(mContext, e);
}
}二是,将任务转交到其他人,只不过它采用的方式是发广播; // Notify the SmsReceiverService to send the message out
Intent intent = new Intent(SmsReceiverService.ACTION_SEND_MESSAGE, null, mContext, SmsReceiver.class);
intent.putExtra(SUBSCRIPTION, mSubscription);
mContext.sendBroadcast(intent);小结:该类做了一个很重要的工作就是讲要发送的短信保存进入数据库,然后发广播通知SmsReceiver;3.4 SmsReceiver 到 SmsReceiverService 简析 实际上SmsReceiver这家伙也不是干事的人,它仅仅是拿到手里后马上就转交给SmsReceiverService服务了,“这事不归我管,我就是一个送快递的“,SmsReceiver的角色就是这样的,调用的方法可以参考时序图;
@Override
public void handleMessage(Message msg) {
int serviceId = msg.arg1;
Intent intent = (Intent)msg.obj;
if (intent != null) {
String action = intent.getAction();
int error = intent.getIntExtra("errorCode", 0);
if (SMS_RECEIVED_ACTION.equals(action)) {
handleSmsReceived(intent, error);
} else if (SMS_CB_RECEIVED_ACTION.equals(action)) {
handleCbSmsReceived(intent, error);
} else if (ACTION_BOOT_COMPLETED.equals(action)) {
handleBootCompleted();
} else if (TelephonyIntents.ACTION_SERVICE_STATE_CHANGED.equals(action)) {
handleServiceStateChanged(intent);
} else if (ACTION_SEND_MESSAGE.endsWith(action)) {
handleSendMessage(intent);
}
}
// NOTE: We MUST not call stopSelf() directly, since we need to
// make sure the wake lock acquired by AlertReceiver is released.
SmsReceiver.finishStartingService(SmsReceiverService.this, serviceId);
}
}这里接收到发送后会走handleSendMessage方法;if (mMessageText == null) {
// Don't try to send an empty message, and destination should be just
// one.
throw new MmsException("Null message body or have multiple destinations.");
}
SmsManager smsManager = SmsManager.getDefault();
ArrayList<String> messages = null;
if ((MmsConfig.getEmailGateway() != null) &&
(Mms.isEmailAddress(mDest) || MessageUtils.isAlias(mDest))) {
String msgText;
msgText = mDest + " " + mMessageText;
mDest = MmsConfig.getEmailGateway();
messages = smsManager.divideMessage(msgText);
} else {
messages = smsManager.divideMessage(mMessageText);
// remove spaces from destination number (e.g. "801 555 1212" -> "8015551212")
mDest = mDest.replaceAll(" ", "");
}
int messageCount = messages.size();
if (messageCount == 0) {
// Don't try to send an empty message.
throw new MmsException("SmsMessageSender.sendMessage: divideMessage returned " +
"empty messages. Original message is \"" + mMessageText + "\"");
}
boolean moved = Sms.moveMessageToFolder(mContext, mUri, Sms.MESSAGE_TYPE_OUTBOX, 0);
if (!moved) {
throw new MmsException("SmsMessageSender.sendMessage: couldn't move message " +
"to outbox: " + mUri);
}
ArrayList<PendingIntent> deliveryIntents = new ArrayList<PendingIntent>(messageCount);
ArrayList<PendingIntent> sentIntents = new ArrayList<PendingIntent>(messageCount);
for (int i = 0; i < messageCount; i++) {
if (mRequestDeliveryReport) {
// TODO: Fix: It should not be necessary to
// specify the class in this intent. Doing that
// unnecessarily limits customizability.
deliveryIntents.add(PendingIntent.getBroadcast(
mContext, 0,
new Intent(
MessageStatusReceiver.MESSAGE_STATUS_RECEIVED_ACTION,
mUri,
mContext,
MessageStatusReceiver.class),
0));
}
Intent intent = new Intent(SmsReceiverService.MESSAGE_SENT_ACTION,
mUri,
mContext,
SmsReceiver.class);
int requestCode = 0;
if (i == messageCount -1) {
// Changing the requestCode so that a different pending intent
// is created for the last fragment with
// EXTRA_MESSAGE_SENT_SEND_NEXT set to true.
requestCode = 1;
intent.putExtra(SmsReceiverService.EXTRA_MESSAGE_SENT_SEND_NEXT, true);
intent.putExtra(SUBSCRIPTION, mSubscription);
}
sentIntents.add(PendingIntent.getBroadcast(mContext, requestCode, intent, 0));
}
try {
smsManager.sendMultipartTextMessage(mDest, mServiceCenter, messages, sentIntents,
deliveryIntents, mSubscription);
} catch (Exception ex) {
throw new MmsException("SmsMessageSender.sendMessage: caught " + ex +
" from SmsManager.sendTextMessage()");
}
if (Log.isLoggable(LogTag.TRANSACTION, Log.VERBOSE)) {
log("sendMessage: address=" + mDest + ", threadId=" + mThreadId +
", uri=" + mUri + ", msgs.count=" + messageCount);
}这部分主要是分析了短息的发送的一个流程,从ui点击button开始到中间层执行发送的操作,当然这里还有很多不详的地方,我也在尝试不断的完善。