(Presentation)     (Training)     (Lab)
•            Jollen’s Consulting

    • http://www.jollen.org/consulting
•                  3G
      www.moko365.com

•
moko365.com
                        	
     	
                                            	
  	
 
                         ...
•   Moko365.com


•
moko365.com
                                                         	
 
          	
 




Android         Copyright (c) 2...
moko365.com



                /&)*!-*'$)&&



                    !"#$%&'




                ()*+)!,&-.$)




Android   ...
moko365.com


            /+0*'"0!.--!"$.4"'+



            /+0*'"0!1*.2)3'*(



                     !"#$%&'




       ...
moko365.com
          	
 
                	
 




Android                     Copyright (c) 2009 Jollen’s Consulting      ...
Every Android application runs in its own                         moko365.com
      process, with its own instance of the ...
moko365.com

                   -*'$)&&



          "+&/.+$)!'0!1.!2"(!34



                    !"#$%&'




            ...
moko365.com
          '$()*)(+       &%"*)$%                  "%$%)*%"    !"#*),%"


          !"#$%&&        !"#$%&&     ...
moko365.com
          '$()*)(+         &%"*)$%                 "%$%)*%"     !"#*),%"


                                   ...
moko365.com




                        $#'!#(%()


                       '*+(!),"%*-


                          !"#$%&&...
moko365.com
          	
                	
                 	
 
                      	
          	
                 	
 


...
Android   Copyright (c) 2009 Jollen’s Consulting         . www.jollen.org/consulting
moko365.com
          	
               	
          	
 




Android               Copyright (c) 2009 Jollen’s Consulting   ...
moko365.com

                	
 




Android               Copyright (c) 2009 Jollen’s Consulting     . www.jollen.org/con...
moko365.com
           	
 
                                          	
                      	
          	
 
           	
...
moko365.com
              !"#$%&&


              '()"*"(%&                                    User-space driver


       ...
moko365.com
              $#'!#(%()                                      API


              '*+(!),"%*-                  ...
moko365.com
              !"#$%&&                                      3.          API


              '()"*"(%&          ...
*
                                                                                              moko365.com
         $#'!#...
moko365.com
      !"#$%&'"(                                    2.          API        native function


                  ...
Android   Copyright (c) 2009 Jollen’s Consulting   . www.jollen.org/consulting
moko365.com
                                     	
             	
                	
          	
 
          	
           	...
moko365.com
          	
                	
                 	
 
                                  	
     	
              	
...
moko365.com

                      	
                                               	
           	
 

                	
  ...
moko365.com
                 	
                            	
        	
 
                       	
          	
            ...
moko365.com
          int hw_get_module(const char *id, const struct hw_module_t **module)




                	
       	
...
moko365.com
                                 Java Stub

                 Service/JNI
          framework/base/services/jni...
moko365.com




Android   Copyright (c) 2009 Jollen’s Consulting   . www.jollen.org/consulting
moko365.com
     class SensorService extends ISensorService.Stub {
         ...
         private static native int _sensor...
moko365.com
    class SensorService extends ISensorService.Stub {
        ...
        public SensorService(Context context...
moko365.com
 static JNINativeMethod gMethods[] = {
     {"_sensors_control_init",     "()I",   (void*) android_init },
   ...
moko365.com

static jint
android_init(JNIEnv *env, jclass clazz)
{
    sensors_module_t* module;
    if (hw_get_module(SEN...
moko365.com

  /**
   * Every hardware module must have a data structure named HAL_MODULE_INFO_SYM
   * and the fields of ...
struct hw_module_t {
          /** tag must be initialized to HARDWARE_MODULE_TAG */
          uint32_t tag;

           /...
moko365.com
  struct hw_module_methods_t {
      /** Open a specific device */
      int (*open)(const struct hw_module_t*...
moko365.com

    static inline int sensors_control_open(const struct hw_module_t* module,
            struct sensors_contr...
moko365.com




Android   Copyright (c) 2009 Jollen’s Consulting   . www.jollen.org/consulting
moko365.com


    static inline int sensors_control_open(const struct hw_module_t* module,
            struct sensors_cont...
moko365.com
 static JNINativeMethod gMethods[] = {
     {"_sensors_control_init",     "()I",   (void*) android_init },
   ...
/**
     * Every device data structure must begin with hw_device_t
                                                       ...
moko365.com




Android   Copyright (c) 2009 Jollen’s Consulting   . www.jollen.org/consulting
/**                                                                 moko365.com
           * Every device data structure m...
Android   Copyright (c) 2009 Jollen’s Consulting         . www.jollen.org/consulting
moko365.com




Android   Copyright (c) 2009 Jollen’s Consulting         . www.jollen.org/consulting
moko365.com

           	
 




Android   Copyright (c) 2009 Jollen’s Consulting   . www.jollen.org/consulting
moko365.com
          on boot
            setprop ro.product.board smdk6410
                                         varie...
!"#$%&


                                                                Manager
                                         ...
Android   Copyright (c) 2009 Jollen’s Consulting     . www.jollen.org/consulting
moko365.com




Android   Copyright (c) 2009 Jollen’s Consulting   . www.jollen.org/consulting
moko365.com




Android   Copyright (c) 2009 Jollen’s Consulting   . www.jollen.org/consulting
moko365.com




Android   Copyright (c) 2009 Jollen’s Consulting   . www.jollen.org/consulting
<?xml version="1.0" encoding="utf-8"?>
 <AbsoluteLayout
 android:id="@+id/widget0"
 android:layout_width="fill_parent"
 an...
/*      setOnClickListener        */
                                                                      mButton1.setOnC...
package led.com.cn;

  import android.util.Log;
                                                                          ...
将                                                贝                          moko365.com
                                  ...
#include <stdio.h>
  #include <stdlib.h>                                                                      moko365.com
...
moko365.com
        $ arm-none-linux-gnueabi-gcc -I/home/online/jdk1.6.0_14/include -I/home/online/jdk1.6.0_14/
        in...
www.moko365.com
Android HAL Introduction: libhardware and its legacy
Android HAL Introduction: libhardware and its legacy
Android HAL Introduction: libhardware and its legacy
Upcoming SlideShare
Loading in...5
×

Android HAL Introduction: libhardware and its legacy

51,891

Published on

Introduction of libhardware and libhardware_legacy, the HAL layer. Also Sensor Service as an example.

Published in: Technology
0 Comments
28 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total Views
51,891
On Slideshare
0
From Embeds
0
Number of Embeds
25
Actions
Shares
0
Downloads
2,391
Comments
0
Likes
28
Embeds 0
No embeds

No notes for slide

Android HAL Introduction: libhardware and its legacy

  1. 1. (Presentation) (Training) (Lab)
  2. 2. • Jollen’s Consulting • http://www.jollen.org/consulting • 3G www.moko365.com •
  3. 3. moko365.com Android Copyright (c) 2009 Jollen’s Consulting . www.jollen.org/consulting
  4. 4. • Moko365.com •
  5. 5. moko365.com Android Copyright (c) 2009 Jollen’s Consulting . www.jollen.org/consulting
  6. 6. moko365.com /&)*!-*'$)&& !"#$%&' ()*+)!,&-.$) Android Copyright (c) 2009 Jollen’s Consulting . www.jollen.org/consulting
  7. 7. moko365.com /+0*'"0!.--!"$.4"'+ /+0*'"0!1*.2)3'*( !"#$%&' ()*+)!,&-.$) Android Copyright (c) 2009 Jollen’s Consulting . www.jollen.org/consulting
  8. 8. moko365.com Android Copyright (c) 2009 Jollen’s Consulting . www.jollen.org/consulting
  9. 9. Every Android application runs in its own moko365.com process, with its own instance of the Dalvik virtual machine. Dalvik has been written so that a device can run multiple VMs efficiently. The Dalvik VM executes files in the Dalvik Executable (.dex) format which is optimized for minimal memory footprint. The VM is register-based, and runs classes compiled by a Java language compiler that have been transformed into the .dex format by the included "dx" tool. --Android Dev Guide Android Copyright (c) 2009 Jollen’s Consulting . www.jollen.org/consulting
  10. 10. moko365.com -*'$)&& "+&/.+$)!'0!1.!2"(!34 !"#$%&' ()*+)!,&-.$) Android Copyright (c) 2009 Jollen’s Consulting . www.jollen.org/consulting
  11. 11. moko365.com '$()*)(+ &%"*)$% "%$%)*%" !"#*),%" !"#$%&& !"#$%&& !"#$%&& !"#$%&& Android Copyright (c) 2009 Jollen’s Consulting . www.jollen.org/consulting
  12. 12. moko365.com '$()*)(+ &%"*)$% "%$%)*%" !"#*),%" !"#$%&& Android Copyright (c) 2009 Jollen’s Consulting . www.jollen.org/consulting
  13. 13. moko365.com $#'!#(%() '*+(!),"%*- !"#$%&& Android Copyright (c) 2009 Jollen’s Consulting . www.jollen.org/consulting
  14. 14. moko365.com Android Copyright (c) 2009 Jollen’s Consulting . www.jollen.org/consulting
  15. 15. Android Copyright (c) 2009 Jollen’s Consulting . www.jollen.org/consulting
  16. 16. moko365.com Android Copyright (c) 2009 Jollen’s Consulting . www.jollen.org/consulting
  17. 17. moko365.com Android Copyright (c) 2009 Jollen’s Consulting . www.jollen.org/consulting
  18. 18. moko365.com Android Copyright (c) 2009 Jollen’s Consulting . www.jollen.org/consulting
  19. 19. moko365.com !"#$%&& '()"*"(%& User-space driver '()$ Standard C Libraries System Calls +%,($%!+"(,%" Linux kernel * : Jollen’s Consulting, for update see jollen.org/consulting Android Copyright (c) 2009 Jollen’s Consulting . www.jollen.org/consulting
  20. 20. moko365.com $#'!#(%() API '*+(!),"%*- Java Thread JNI !"#$%&& Dalvik VM ./0!1)23 *.so 4+3$ Standard C Libraries System Calls -%5+$%!-"+5%" Linux kernel * : Jollen’s Consulting, for update see jollen.org/consulting Android Copyright (c) 2009 Jollen’s Consulting . www.jollen.org/consulting
  21. 21. moko365.com !"#$%&& 3. API '()"*"(%& 2. API library '()$ Standard C Libraries +%,($%!+"(,%" 1. * * : Jollen’s Consulting, for update see jollen.org/consulting Android Copyright (c) 2009 Jollen’s Consulting . www.jollen.org/consulting
  22. 22. * moko365.com $#'!#(%() API !"#$%&'"( '*+(!),"%*- Dalvik )#*+,(!-.!/ 0'"%!1,2"#"3 !"#$%&& Core Libraries ./0!1)23 *.so 451!6782 4+3$ Standard C Libraries *,29 -%5+$%!-"+5%" Linux kernel :%+,9%!:",+%" * : Jollen’s Consulting, for update see jollen.org/consulting Android Copyright (c) 2009 Jollen’s Consulting . www.jollen.org/consulting
  23. 23. moko365.com !"#$%&'"( 2. API native function 3. JNI method table )#*+,(!-.!/ 0'"%!1,2"#"3 5. core libraries 451!6782 4. callback functions supporting API *,29 Standard C Libraries :%+,9%!:",+%" 1. * : Jollen’s Consulting, for update see jollen.org/consulting Android Copyright (c) 2009 Jollen’s Consulting . www.jollen.org/consulting
  24. 24. Android Copyright (c) 2009 Jollen’s Consulting . www.jollen.org/consulting
  25. 25. moko365.com Android Copyright (c) 2009 Jollen’s Consulting . www.jollen.org/consulting
  26. 26. moko365.com Android Copyright (c) 2009 Jollen’s Consulting . www.jollen.org/consulting
  27. 27. moko365.com Android Copyright (c) 2009 Jollen’s Consulting . www.jollen.org/consulting
  28. 28. moko365.com Android Copyright (c) 2009 Jollen’s Consulting . www.jollen.org/consulting
  29. 29. moko365.com int hw_get_module(const char *id, const struct hw_module_t **module) Android Copyright (c) 2009 Jollen’s Consulting . www.jollen.org/consulting
  30. 30. moko365.com Java Stub Service/JNI framework/base/services/jni HAL hardware/libhardware HAL Stub sysfs /sys Kernel Modules Android Copyright (c) 2009 Jollen’s Consulting . www.jollen.org/consulting
  31. 31. moko365.com Android Copyright (c) 2009 Jollen’s Consulting . www.jollen.org/consulting
  32. 32. moko365.com class SensorService extends ISensorService.Stub { ... private static native int _sensors_control_init(); private static native ParcelFileDescriptor _sensors_control_open(); private static native boolean _sensors_control_activate(int sensor, boolean activate); private static native int _sensors_control_set_delay(int ms); } at framework/base/services/java/SensorService.java Android Copyright (c) 2009 Jollen’s Consulting . www.jollen.org/consulting
  33. 33. moko365.com class SensorService extends ISensorService.Stub { ... public SensorService(Context context) { if (localLOGV) Log.d(TAG, "SensorService startup"); _sensors_control_init(); mNotificationManager = (NotificationManager)context.getSystemService (Context.NOTIFICATION_SERVICE); mContext = context; } ... } at framework/base/services/java/SensorService.java Android Copyright (c) 2009 Jollen’s Consulting . www.jollen.org/consulting
  34. 34. moko365.com static JNINativeMethod gMethods[] = { {"_sensors_control_init", "()I", (void*) android_init }, {"_sensors_control_open", "()Landroid/os/ParcelFileDescriptor;", (void*) android_open }, {"_sensors_control_activate", "(IZ)Z", (void*) android_activate }, {"_sensors_control_wake", "()I", (void*) android_data_wake }, {"_sensors_control_set_delay","(I)I", (void*) android_set_delay }, }; at framework/base/services/jni/com_android_server_SensorService.cpp Android Copyright (c) 2009 Jollen’s Consulting . www.jollen.org/consulting
  35. 35. moko365.com static jint android_init(JNIEnv *env, jclass clazz) { sensors_module_t* module; if (hw_get_module(SENSORS_HARDWARE_MODULE_ID, (const hw_module_t**)&module) == 0) { if (sensors_control_open(&module->common, &sSensorDevice) == 0) { const struct sensor_t* list; int count = module->get_sensors_list(module, &list); return count; } } return 0; } #define SENSORS_MODULE_ID “sensors” Android Copyright (c) 2009 Jollen’s Consulting . www.jollen.org/consulting
  36. 36. moko365.com /** * Every hardware module must have a data structure named HAL_MODULE_INFO_SYM * and the fields of this data structure must begin with hw_module_t * followed by module specific information. */ struct sensors_module_t { struct hw_module_t common; /** * Enumerate all available sensors. The list is returned in "list". * @return number of sensors in the list */ int (*get_sensors_list)(struct sensors_module_t* module, struct sensor_t const** list); }; supporting API HAL stub Android Copyright (c) 2009 Jollen’s Consulting . www.jollen.org/consulting
  37. 37. struct hw_module_t { /** tag must be initialized to HARDWARE_MODULE_TAG */ uint32_t tag; /** major version number for the module */ moko365.com uint16_t version_major; /** minor version number of the module */ uint16_t version_minor; /** Identifier of module */ const char *id; /** Name of this module */ const char *name; /** Author/owner/implementor of the module */ const char *author; /** Modules methods */ struct hw_module_methods_t* methods; /** padding to 128 bytes, reserved for future use */ uint32_t reserved[32-6]; }; Android Copyright (c) 2009 Jollen’s Consulting . www.jollen.org/consulting
  38. 38. moko365.com struct hw_module_methods_t { /** Open a specific device */ int (*open)(const struct hw_module_t* module, const char* id, struct hw_device_t** device); }; Android Copyright (c) 2009 Jollen’s Consulting . www.jollen.org/consulting
  39. 39. moko365.com static inline int sensors_control_open(const struct hw_module_t* module, struct sensors_control_device_t** device) { return module->methods->open(module, SENSORS_HARDWARE_CONTROL, (struct hw_device_t**)device); } at hardware/libhardware/include/hardware/sensors.h Android Copyright (c) 2009 Jollen’s Consulting . www.jollen.org/consulting
  40. 40. moko365.com Android Copyright (c) 2009 Jollen’s Consulting . www.jollen.org/consulting
  41. 41. moko365.com static inline int sensors_control_open(const struct hw_module_t* module, struct sensors_control_device_t** device) { return module->methods->open(module, SENSORS_HARDWARE_CONTROL, (struct hw_device_t**)device); } struct hw_module_methods_t { /** Open a specific device */ int (*open)(const struct hw_module_t* module, const char* id, struct hw_device_t** device); }; at hardware/libhardware/include/hardware/sensors.h Android Copyright (c) 2009 Jollen’s Consulting . www.jollen.org/consulting
  42. 42. moko365.com static JNINativeMethod gMethods[] = { {"_sensors_control_init", "()I", (void*) android_init }, {"_sensors_control_open", "()Landroid/os/ParcelFileDescriptor;", (void*) android_open }, {"_sensors_control_activate", "(IZ)Z", (void*) android_activate }, {"_sensors_control_wake", "()I", (void*) android_data_wake }, {"_sensors_control_set_delay","(I)I", (void*) android_set_delay }, }; Android Copyright (c) 2009 Jollen’s Consulting . www.jollen.org/consulting
  43. 43. /** * Every device data structure must begin with hw_device_t moko365.com * followed by module specific public methods and attributes. */ struct sensors_control_device_t { struct hw_device_t common; /** * Returns the fd which will be the parameter to * sensors_data_device_t::open_data(). * The caller takes ownership of this fd. This is intended to be * passed cross processes. * * @return a fd if successful, < 0 on error */ int (*open_data_source)(struct sensors_control_device_t *dev); int (*activate)(struct sensors_control_device_t *dev, int handle, int enabled); int (*set_delay)(struct sensors_control_device_t *dev, int32_t ms); int (*wake)(struct sensors_control_device_t *dev); }; Android Copyright (c) 2009 Jollen’s Consulting . www.jollen.org/consulting
  44. 44. moko365.com Android Copyright (c) 2009 Jollen’s Consulting . www.jollen.org/consulting
  45. 45. /** moko365.com * Every device data structure must begin with hw_device_t * followed by module specific public methods and attributes. */ struct hw_device_t { /** tag must be initialized to HARDWARE_DEVICE_TAG */ uint32_t tag; /** version number for hw_device_t */ uint32_t version; /** reference to the module this device belongs to */ struct hw_module_t* module; /** padding reserved for future use */ uint32_t reserved[12]; /** Close this device */ int (*close)(struct hw_device_t* device); }; Android Copyright (c) 2009 Jollen’s Consulting . www.jollen.org/consulting
  46. 46. Android Copyright (c) 2009 Jollen’s Consulting . www.jollen.org/consulting
  47. 47. moko365.com Android Copyright (c) 2009 Jollen’s Consulting . www.jollen.org/consulting
  48. 48. moko365.com Android Copyright (c) 2009 Jollen’s Consulting . www.jollen.org/consulting
  49. 49. moko365.com on boot setprop ro.product.board smdk6410 varient key prop /system/lib/hw/sensors.smdk6410.so <MODULE_ID>.<prop>.so setprop <variant_key> <property> Android Copyright (c) 2009 Jollen’s Consulting . www.jollen.org/consulting
  50. 50. !"#$%& Manager moko365.com framework/base/services/java Dalvik VM IStubService Service/Java framework/base/services/java register JNI Table Android server Service/JNI framework/base/services/jni HAL hardware/libhardware HAL Stub sysfs /sys VM Onload App Onload Android Copyright (c) 2009 Jollen’s Consulting . www.jollen.org/consulting
  51. 51. Android Copyright (c) 2009 Jollen’s Consulting . www.jollen.org/consulting
  52. 52. moko365.com Android Copyright (c) 2009 Jollen’s Consulting . www.jollen.org/consulting
  53. 53. moko365.com Android Copyright (c) 2009 Jollen’s Consulting . www.jollen.org/consulting
  54. 54. moko365.com Android Copyright (c) 2009 Jollen’s Consulting . www.jollen.org/consulting
  55. 55. <?xml version="1.0" encoding="utf-8"?> <AbsoluteLayout android:id="@+id/widget0" android:layout_width="fill_parent" android:layout_height="fill_parent" xmlns:android="http://schemas.android.com/apk/res/android" moko365 .com > <Button android:id="@+id/myButton1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:textSize="18sp" android:text=" LED" android:layout_x="70px" android:layout_y="88px" > </Button> <Button android:id="@+id/myButton2" <Button android:layout_width="wrap_content" android:id="@+id/myButton3" android:layout_height="wrap_content" android:layout_width="wrap_content" android:text=" LED" android:layout_height="wrap_content" android:textSize="18sp" android:textSize="18sp" android:layout_x="184px" android:text="Exit" android:layout_y="88px" android:layout_x="130px" > android:layout_y="150px" </Button> > </Button> </AbsoluteLayout> Android Copyright (c) 2009 Jollen’s Consulting . www.jollen.org/consulting
  56. 56. /* setOnClickListener */ mButton1.setOnClickListener(new Button.OnClickListener() package led.com.cn; { import android.app.Activity; @Override import android.os.Bundle; /* onClick */ import android.view.View; public void onClick(View v) moko365.com import android.widget.Button; { // TODO Auto-generated method stub public class Led_control extends Activity { /** Called when the activity is first created. */ setTitle("LED !"); /* 3 Button private */ /* 4 LED */ private Button mButton1; Linuxc.send(num, led_on); private Button mButton2; private Button mButton3; } }); /* LED */ mButton2.setOnClickListener(new Button.OnClickListener() public int num = 4; { /* 1 */ @Override public int led_on = 1; public void onClick(View v) /* 2 */ { public int led_off = 2; // TODO Auto-generated method stub public int fd = 0; setTitle("LED !"); /* 4 LED */ @Override Linuxc.send(num, led_off); public void onCreate(Bundle savedInstanceState) { } super.onCreate(savedInstanceState); }); setContentView(R.layout.main); mButton3.setOnClickListener(new Button.OnClickListener() mButton1 =(Button) findViewById(R.id.myButton1); { mButton2 =(Button) findViewById(R.id.myButton2); @Override mButton3 =(Button) findViewById(R.id.myButton3); public void onClick(View v) { /* led fd */ // TODO Auto-generated method stub fd = Linuxc.openled(); /* */ if (fd < 0){ Linuxc.closeled(); setTitle(" "); /* */ finish(); finish(); /* */ } } }); else { setTitle(" "); } }} } Android Copyright (c) 2009 Jollen’s Consulting . www.jollen.org/consulting
  57. 57. package led.com.cn; import android.util.Log; moko365.com public class Linuxc { static { try { Log.i("JNI", "Trying to load libled.so"); /* libled.so */ System.loadLibrary("led"); } catch (UnsatisfiedLinkError ule) { Log.e("JNI", "WARNING: Could not load libled.so"); }} /* openled() */ public static native int openled(); /* closeled () */ public static native int closeled(); /* send() */ public static native int send(int led_num, int on_off); } Android Copyright (c) 2009 Jollen’s Consulting . www.jollen.org/consulting
  58. 58. 将 贝 moko365.com 录 个 头 数声 头 $ mkdir led_test $ cd led_test ... $ /javah -classpath ~/Led_Control/bin/ led.com.cn.Linuxc Android Copyright (c) 2009 Jollen’s Consulting . www.jollen.org/consulting
  59. 59. #include <stdio.h> #include <stdlib.h> moko365.com #include <fcntl.h> #include <errno.h> #include <unistd.h> #include <sys/ioctl.h> #include "led_com_cn_Linuxc.h" #include "led.h" #define LED_TEST 3 #define DEVICE_BLTEST "/dev/led" int fd; JNIEXPORT jint JNICALL Java_led_com_cn_Linuxc_openled (JNIEnv *env, jclass mc) { fd= open(DEVICE_BLTEST,O_RDONLY); return fd; } JNIEXPORT jint JNICALL Java_led_com_cn_Linuxc_closeled (JNIEnv *env, jclass mc) { close(fd); } JNIEXPORT jint JNICALL Java_led_com_cn_Linuxc_send (JNIEnv *env, jclass mc, jint a, jint b) { ioctl(fd,b,&a); } Android Copyright (c) 2009 Jollen’s Consulting . www.jollen.org/consulting
  60. 60. moko365.com $ arm-none-linux-gnueabi-gcc -I/home/online/jdk1.6.0_14/include -I/home/online/jdk1.6.0_14/ include/linux -fpic -c led_com_cn_linuxc.c $arm-none-linux-gnueabi-ld-T /home/online/CodeSourcery/Sourcery_G++_Lite/arm-none-linux- gnueabi/lib/ldscripts/armelf_linux_eabi.xsc -shared -o libled.so led_com_cn_linuxc.o Android Copyright (c) 2009 Jollen’s Consulting . www.jollen.org/consulting
  61. 61. www.moko365.com
  1. A particular slide catching your eye?

    Clipping is a handy way to collect important slides you want to go back to later.

×