2016年1月21日 星期四

樣板類, 樣板函數


C++類模板詳解

如果說類是對象的抽象,對象是類的實例,則類模板是類的抽象,類是類模板的實例

C++函數模板

2016年1月11日 星期一

[轉] Creating an Android Emulator Quickly

Here's how to setup an Android Phone emulator, make sure the SDK + tools are installed (see my first post). You might have multiple Android SDK target versions to see which Android versions you have installed run the following:


ff@shoryuken:~/android-sdks/tools$ ./android list
Available Android targets:
----------
id: 1 or "android-7"
Name: Android 2.1
Type: Platform
API level: 7
Revision: 3
Skins: WQVGA400, WQVGA432, HVGA, WVGA800 (default), WVGA854, QVGA
ABIs : armeabi
----------
id: 2 or "android-14"
Name: Android 4.0
Type: Platform
API level: 14
Revision: 3
Skins: WQVGA400, WQVGA432, HVGA, WVGA800 (default), WXGA720, WSVGA, WVGA854, QVGA, WXGA800
ABIs : no ABIs.
----------
id: 3 or "android-15"
Name: Android 4.0.3
Type: Platform
API level: 15
Revision: 1
Skins: WQVGA400, WQVGA432, HVGA, WVGA800 (default), WXGA720, WSVGA, WVGA854, QVGA, WXGA800
ABIs : armeabi-v7a
----------
id: 4 or "Google Inc.:Google APIs:15"Name: Google APIs
Type: Add-On
Vendor: Google Inc.
Revision: 1
Description: Android + Google APIs
Based on Android 4.0.3 (API level 15)
Libraries:
* com.google.android.media.effects (effects.jar)
Collection of video effects
* com.android.future.usb.accessory (usb.jar)
API for USB Accessories
* com.google.android.maps (maps.jar)
API for Google Maps
Skins: WVGA854, WQVGA400, WSVGA, WXGA720, HVGA, WQVGA432, QVGA, WVGA800 (default), WXGA800
ABIs : armeabi-v7a
Available Android Virtual Devices:
Name: galaxy
Path: /home/ff/.android/avd/galaxy.avd
Target: Android 4.0.3 (API level 15)
ABI: armeabi-v7a
Skin: WVGA800

In my case I would like to emulate id 4 ("id: 4 or "Google Inc.:Google APIs:15"
") so I would run the following command:

ff@shoryuken:~/android-sdks/tools$ ./android create avd -n phoneA -t 4        (choose from android list  Android技術內幕系統卷)
Created AVD 'phoneA' based on Google APIs (Google Inc.), ARM (armeabi-v7a) processor,
with the following hardware config:
hw.lcd.density=240
vm.heapSize=48
hw.ramSize=512


Now to run the emulator we type: 
ff@shoryuken:~/android-sdks/tools$ ./emulator -avd phoneA &
./emulator -avd phoneA -system system.img -data userdata.img -ramdisk ramdisk.img



We're done!

Getting the SDcard can be found here. 
http://blog.jayway.com/2009/04/22/working-with-sd-cards-in-the-android-emulator/

The quick version is simply cd into the tools directory under the android sdk:

$ cd /home/ff/android-sdks/tools
$ ff@shoryuken:~/android-sdks/tools$./mksdcard 128M phoneAsdCard
$ ff@shoryuken:~/android-sdks/tools$ mkdir sdcardA
$ ff@shoryuken:~/android-sdks/tools$ sudo mount -o loop phoneAsdCard sdcardA/
$ ff@shoryuken:~/android-sdks/tools$ ./emulator -avd phoneA -sdcard ./phoneAsdCard

2016年1月6日 星期三

[轉] Binder 機制詳解—Binder 本地框架

http://www.cloudchou.com/android/post-547.html


Binder本地框架

本地Binder框架包含以下類(frameworks/native/libs/binder):
RefBase, IInterface,BnInterface,BpInterface,BpRefBase,Parcel 等等
下圖描述了實例《Binder service入門–創建native binder service》使用的ITestService與本地Binder框架類庫的關係:(若看不清,請點擊看大圖)
native_binde_framework
  • 1) RefBase類(frameworks/native/include/utils/RefBase.h)

    引用的基類,android本地代碼裡採用了智能指針,有強指針,也有弱指針。不過不用糾結於這些細節。
  • 2) IInterface(frameworks/native/include/binder/IInterface.h)

    自定義的binder service接口必須繼承自IInterface(如ITestService),它的onAsBinder方法為抽象方法,該方法的實現在BpInterface和BnInterface模版類裡。
  • 3) BpRefBase(frameworks/native/include/binder/Binder.h)

    客戶端間接用到該類,用於保存IBinder指針,remote()方法即返回IBinder指針。
  • 4) ITestService

    聲明的binder service接口,在該接口裡會聲明所有提供的服務方法(使用純虛函數),並用宏DECLARE_META_INTERFACE進行聲明,這樣會添加靜態字段descriptor,靜態方法asInterface,虛方法getInterfaceDescriptor,以及構造函數和析構函數。另外只需要使用IMPLEMENT_META_INTERFACE(INTERFACE, NAME)來即可定義用宏DECLARE_META_INTERFACE聲明的這些方法和字段。
    DECLARE_META_INTERFACE宏的源碼如下所示:
    1
    2
    3
    4
    5
    6
    7
    
    #define DECLARE_META_INTERFACE(INTERFACE)                           \
        static const android::String16 descriptor;                      \
        static android::sp<I##INTERFACE> asInterface(                   \
                const android::sp<android::IBinder>& obj);              \
        virtual const android::String16& getInterfaceDescriptor() const;\
        I##INTERFACE();                                                 \
        virtual ~I##INTERFACE();
    若使用DECLARE_META_INTERFACE(TestService); 則會擴展為:
    1
    2
    3
    4
    5
    6
    
    static const android::String16 descriptor;                       \
    static android::sp<ITestService> asInterface(                    \
                const android::sp<android::IBinder>& obj);           \
    virtual const android::String16& getInterfaceDescriptor() const; \
    ITestService();                                                  \
    virtual ~ITestService();
    宏函數IMPLEMENT_META_INTERFACE(INTERFACE, NAME)的源碼如下所示:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    
    #define IMPLEMENT_META_INTERFACE(INTERFACE, NAME)              \
        const android::String16 I##INTERFACE::descriptor(NAME);    \
        const android::String16&                                   \
                I##INTERFACE::getInterfaceDescriptor() const {     \
            return I##INTERFACE::descriptor;                       \
        }                                                          \
        android::sp<I##INTERFACE> I##INTERFACE::asInterface(       \
                const android::sp<android::IBinder>& obj)          \
        {                                                          \
            android::sp<I##INTERFACE> intr;                        \
            if (obj != NULL) {                                     \
                intr = static_cast<I##INTERFACE*>(                 \
                    obj->queryLocalInterface(                      \
                            I##INTERFACE::descriptor).get());      \
                if (intr == NULL) {                                \
                    intr = new Bp##INTERFACE(obj);                 \
                }                                                  \
            }                                                      \
            return intr;                                           \
        }                                                          \
        I##INTERFACE::I##INTERFACE() { }                           \
        I##INTERFACE::~I##INTERFACE() { }                          \
    若使用IMPLEMENT_META_INTERFACE(TestService, 「android.TestServer.ITestService」)則會被替換成:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    
    const android::String16 
        ITestService::descriptor("android.TestServer.ITestService"); \
        const android::String16&                                     \
                ITestService::getInterfaceDescriptor() const {       \
            return ITestService::descriptor;                         \
        }                                                            \
        android::sp<ITestService> ITestService::asInterface(         \
                const android::sp<android::IBinder>& obj)            \
        {                                                            \
            android::sp<ITestService> intr;                          \
            if (obj != NULL) {                                       \
                intr = static_cast<ITestService*>(                   \
                    obj->queryLocalInterface(                        \
                            ITestService::descriptor).get());        \
                if (intr == NULL) {                                  \
                    intr = new BpTestService(obj);                   \
                }                                                    \
            }                                                        \
            return intr;                                             \
        }                                                            \
        ITestService::ITestService() { }                             \
        ITestService::~ITestService() { }                            \
  • 5) BpInterface(frameworks/native/include/binder/Binder.h)

    該類是一個模版類,需和某個繼承自IIterface的類結合使用。
    它的聲明如下所示:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    
     template<typename INTERFACE>
    class BpInterface : public INTERFACE, public BpRefBase
    {
    public:
                                    BpInterface(const sp<IBinder>& remote);
     
    protected:
        virtual IBinder*            onAsBinder();
    };
    因此BpInterface會繼承兩個類,一個父類是繼承自IInterface的類,一個是BpRefbase,我們通常聲明的客戶端代理類會繼承自BpInterface
  • 6) BnInterface(frameworks/native/include/binder/IInterface.h)

    該類也是一個模版類,需和某個繼承自IIterface的類結合使用。
    它的聲明如下所示:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    
     template<typename INTERFACE>
    class BnInterface : public INTERFACE, public BBinder
    {
    public:
        virtual sp<IInterface>      
            queryLocalInterface(const String16& _descriptor);
        virtual const String16&     getInterfaceDescriptor() const;
     
    protected:
        virtual IBinder*            onAsBinder();
    };
    因此BnInterface也會繼承兩個類,一個父類是繼承自IInterface的binder service接口類,一個是代表Binder service服務端的BBinder類,我們通常聲明的服務端類會直接繼承自BnInterface。
    該類實現了IBinder聲明的另外兩個方法,queryLocalInterface和getInterfaceDescriptor。
再介紹一個重要的宏函數interface_cast,它的源碼如下所示:
1
2
3
4
5
template<typename INTERFACE>
inline sp<INTERFACE> interface_cast(const sp<IBinder>& obj)
{
    return INTERFACE::asInterface(obj);
}
若使用interface_cast < ITestService > (binder),會被擴展為:
1
2
3
4
inline sp< ITestService > interface_cast(const sp<IBinder>& obj)
{
    return ITestService::asInterface(obj);
}
而ITestService::asInterface方法是ITestService接口聲明時使用DECLARE_META_INTERFACE(TestService)聲明的函數

IServiceManager類圖

從先前的博客《Binder IPC程序結構》可知,servicemanager其實是init.rc裡聲明的本地服務,由init進程啟動它作為一個單獨的進程運行。不管是提供binder service的服務端還是使用binder service的客戶端,都是在單獨的進程,他們都需要首先獲得servicemananger的IBinder指針,然後利用IBinder指針建立IServiceManager接口對象。通過《Binder 機制詳解—重要函數調用流程分析》我們已經知道如何獲得servicemananger的IBinder指針,並利用該IBinder指針建立IServiceMananger接口對象。
IServiceManager相關類如下圖所示:(若看不清,請點擊看大圖)
native_binder_framework_servicemananger
IServiceManager是表示servicemanager的接口,有如下方法:
1) getService獲得binder service引用,
2) checkService獲得binder service引用,
3) addService添加binder service,
4) listServices 列舉所有binder service。
servicemanager的binder service服務端其實是在frameworks/base/cmds/servicemanager 裡實現,BnServiceMananger實際上並未使用。BpServiceMananger就是利用獲得的IBinder指針建立的IServiceMananger對象的實際類型。

2016年1月5日 星期二

[轉] 淺談ThreadPool 線程池

相關概念:
    線程池可以看做容納線程的容器;
    一個應用程序最多只能有一個線程池;
    ThreadPool靜態類通過QueueUserWorkItem()方法將工作函數排入線程池;
    每排入一個工作函數,就相當於請求創建一個線程;

線程池的作用:
線程池是為突然大量爆發的線程設計的,通過有限的幾個固定線程為大量的操作服務,減少了創建和銷毀線程所需的時間,從而提高效率。
如果一個線程的時間非常長,就沒必要用線程池了(不是不能作長時間操作,而是不宜。),況且我們還不能控制線程池中線程的開始、掛起、和中止。

什麼時候使用ThreadPool

ThreadPool 示例一 :
複製代碼
ThreadPool_1.cs
using System;using System.Text;using System.Threading;
namespace 多線程
{
    
public class Example
    {
        
public static void Main()
        {
            
// Queue the task.
            ThreadPool.QueueUserWorkItem(new WaitCallback(ThreadProc));

            Console.WriteLine(
"Main thread does some work, then sleeps.");
          
            Thread.Sleep(
1000);

            Console.WriteLine(
"Main thread exits.");
        }

        
static void ThreadProc(Object stateInfo)
        {
            
// No state object was passed to QueueUserWorkItem, 
            
// so stateInfo is null.
            Console.WriteLine("Hello from the thread pool.");
        }
    }
}
複製代碼

ThreadPool 示例 :
複製代碼
ThreadPool_2.cs
using System;using System.Collections.Generic;using System.Text;using System.Threading;
namespace CS_Test
{
    
class ThreadPool_Demo
    {
        
// 用於保存每個線程的計算結果
        static int[] result = new int[10];


        
//注意:由於WaitCallback委託的聲明帶有參數,
        
//      所以將被調用的Fun方法必須帶有參數,即:Fun(object obj)。
        static void Fun(object obj)
        {
            
int n = (int)obj;

            
//計算階乘
            int fac = 1;
            
for (int i = 1; i <= n; i++)
            {
                fac 
*= i;
            }
            
//保存結果
            result[n] = fac;
        }

        
static void Main(string[] args)
        {
            
//向線程池中排入9個工作線程
            for (int i = 1; i <= 9 ; i++)
            {
                
//QueueUserWorkItem()方法:將工作任務排入線程池。
                ThreadPool.QueueUserWorkItem(new WaitCallback(Fun),i);
                
// Fun 表示要執行的方法(與WaitCallback委託的聲明必須一致)。
                
// i   為傳遞給Fun方法的參數(obj將接受)。
            }

            
//輸出計算結果
            for (int i = 1; i <= 9; i++)
            {
                Console.WriteLine(
"線程{0}: {0}! = {1}",i,result[i]);
            }
        }

    }
}
複製代碼


ThreadPool的作用:


kernel user space howto

http://people.ee.ethz.ch/~arkeller/linux/multi/


Sending Signals from the Kernel to the User Space

2015年12月28日 星期一

[轉] Android - Intent呼叫第三方程式 (setComponent)

只要利用adb logcat ,再搭配使用setComponet(),就可以輕易的呼叫第三方程式(不在自己的application內)。
詳細用法參考原文:
http://developer.android.com/reference/android/content/Intent.html#setComponent%28android.content.ComponentName%29

比如我自己的程式想執行Android裡面的Settings,先用adb logcat看系統是如何呼叫Settings的

I/ActivityManager(   60): Starting activity: Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10200000 cmp=com.android.settings/.Settings }
I/ActivityManager(   60): Displayed activity com.android.settings/.Settings: 1205 ms (total 1205 ms)

只要有這個cmp就可以呼叫Settings了

public class Main extends Activity {
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Intent i = new Intent();
        ComponentName comp = new ComponentName("com.android.settings", "com.android.settings.Settings");
        i.setComponent(comp);
        startActivity(i);    
    }
}

另外有些程式要被執行,Intent還要多加搭配Intent.setData()或者是Intent.setAction()等方式。比如:想要開啟Browser,而且是開啟tw.yahoo.com的網頁,程式碼如下:
        Intent i = new Intent();
        ComponentName comp = new ComponentName("com.android.browser", "com.android.browser.BrowserActivity");
        i.setComponent(comp);
        Uri uri = Uri.parse("http://tw.yahoo.com");
        i.setData(uri);
        i.setAction(Intent.ACTION_VIEW);
        startActivity(i);