Your SlideShare is downloading. ×
0
High Performance
Android App. Development
양정수 (Jeongsoo Yang)
yangjeongsoo at gmail.com
www.kandroid.org
CONTENT
1. The History of Android Performance Features
2. Performance Comparison
of the Three Programming Models
3. Case S...
Let’s go back to last summer.
“Why will Android always lag behind iOS?”
If you are a manufacturer,
how would you solve thi...
The history of Android Performance Features
• Android alpha (at least two internal releases)

• Android beta (5 Nov. 2007)...
Fast & Smooth - Jelly Bean and Project Butter

Source : http://www.youtube.com/watch?v=V5E5revikUU
Facebook Android Development :
A Scrolling Performance Story - Dec 5, 2012
Their Android Performance Challenges
•
•
•
•
•
...
The World of List View
Tuesday, June 1, 2010, Google I/O
FPS
60
50
40
30
20
10
0

Dumb

Recycling views

ViewHolder

Sourc...
Memory and Performance
March 29, 2013, 11th Kandroid Conference
Event

(AdapterView)
Invalidate

Measurement

A

Adapter

...
What lessons can we learn from history?
1. Always Measure
• Before beginning optimization, ensure the
problem requires sol...
CONTENT
1. The History of Android Performance Features
2. Performance Comparison
of the Three Programming Models
3. Case S...
Comparison and Analysis of
the Three Programming Models
in Google Android (2012, Intel)
• What are the Three Programming M...
What are the Three Programming Models?
2008

2009

M

AOSP
Branch
SDK
(API Level)
NDK
(Revision)

RenderScript
android.sup...
Experiment setup : Balls
SDK : Workflow & Execution Model
Android Runtime

Android SDK
JDK

Input
Source
Program

Java
Compiler

Bytecode
(class Fi...
SDK : Workflow & Execution Model
TLS

Activity
Thread

Queue

Thread Pool

H
handleMessage()

Looper

execute()
ViewRootIm...
NDK : Workflow & Execution Model
A PPLICATIONS

A PPLICATIONS
HelloAndroid

ActivityThread

Receiver

H

Looper

Handle
Me...
RenderScript : Workflow & Execution Model
App Java
Sources

App Java
Sources

Reflected
Layer
(C99)
helloworld.rs

Native ...
RenderScript : Workflow & Execution Model
Framework
Layer
App Java
App Java
App Java
Sources
Sources
Sources

Dalvik
JIT
C...
Performance Analysis : Multiple Worker Thread
70

60

50
SDK
40
SDK-MT
30

NDK
NDK-MT

20

10

0
200

300

400

500

600

...
Performance Analysis : Runtime design diff.
70

60

50

40

SDK-MT
NDK-MT

30

Renderscript

20

10

0
200

300

400

500
...
Current Issues & Unified Programming Model
2
Class

Programmability

Sub Class

SDK

NDK + RS

X

X

X

3

Library
Extensi...
Current Issues & Unified Programming Model
GDK : What is GDK?

Hooray! We done the GDK building system.
This building syst...
GDK : hello-llvm Sample Code

Android-portable.mk
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := hello...
$ ../../../gdk-build --ndk-root=/home/jsyang/android-ndk-r8b
Compile Bitcode : hello_llvm <= hello_llvm.c
Compile++ Bitcod...
Google I/O 2013 : Game Development Env.

An Introduction to
Play Game Services

Game Services
In Practice
CONTENT
1. The History of Android Performance Features
2. Performance Comparison
of the Three Programming Models
3. Case S...
Google I/O 2012 Keynote

Android vs. Chrome
Google I/O 2013 Keynote
Sundar Pichai (SVP, Android, Chrome & Apps)
Performance Features
of the Google Chrome Browser
• Why did Google Develop Chrome?
• Chrome’s Multi-process Architecture o...
Why did Google Develop Chrome?
Chromium

Chrome browser :
uses multiple processes !

Chromium

safer

Sandbox the web app’...
Chrome’s Multi-process Architecture on Android

Source : https://sites.google.com/a/chromium.org/dev/developers/design-doc...
Chrome’s Multi-process Architecture on Android
Browser Process
Main
Thread
(UI)

I/O
Thread

Render Process

IPC

Main
Thr...
Chrome’s Hardware Acceleration on Android
Software Rendering Architecture

Render Process

Shared
Memory

HWND

Bitmap

We...
Chrome’s Hardware Acceleration on Android
Compositing with the GPU process

Browser
Process
HWND

Shared
Memory
Render Pro...
Chrome’s Hardware Acceleration on Android
Compositing with the GPU process
Chrome’s Hardware Acceleration on Android
Compositing with the GPU Thread
USER
u0_a94
u0_a94
u0_a94
u0_a94
u0_a94
u0_a94
u...
Chrome’s Hardware Acceleration on Android

systrace, chrome://gpu
Improved VSync Scheduling on Android
Improved vsync scheduling for Chrome on
Android - Author: skyostil@
• Motivation
• Im...
Google I/O 2012 : For Butter or Worse - VSync
VSync

Drawing
without
VSync

0

VSync

1

1

1

2

3

CPU

3

3

Display
GP...
Improved VSync Scheduling on Android
Old Architecture

System VSync

Browser
Process

internal
timer’s tick

Render
Proces...
Improved VSync Scheduling on Android
Old Architecture
~3.2ms
System VSync
internal
timer’s tick

Browser
Process

Render
P...
Improved VSync Scheduling on Android
Old Architecture and Problems

Source : https://docs.google.com/a/chromium.org/docume...
Improved VSync Scheduling on Android
New Architecture
~3.2ms
System VSync
internal
timer’s tick

Browser
Process

Render
P...
Improved VSync Scheduling on Android
New Architecture : Improvement and Problem

Source : https://docs.google.com/a/chromi...
Improved VSync Scheduling on Android
New Architecture : Improvement and Limit

Conclusion
This document describes improvem...
What lessons can we learn from Chrome?
1. On a GUI system, a scheduler for input and drawing
is the most important .
2. If...
CONTENT
1. The History of Android Performance Features
2. Performance Comparison
of the Three Programming Models
3. Case S...
Multi-Core vs. GPU
~12GB/s

ISP

70GFLOPs

LPDDR3
GPU

CPU

DSP

~20GFLOPs

Dark Silicon and the End of Multicore Scaling
...
Android vs. Chrome
We have two options: The first is maintaining the status
quo, the other is merging the two platforms.

...
Android vs. Chrome
For Android-centric merger to succeed,
we must answer one question:

“Is it possible to build chrome
vi...
Beyond Android
With the current market saturation, is it possible to create
a new platform?
• B2G, Tizen, LG Web OS, Ubunt...
CONTENT
1. The History of Android Performance Features

2. Performance Comparison of the Three
3.
4.

Programming Models
C...
Upcoming SlideShare
Loading in...5
×

Kandroid for nhn_deview_20131013_v5_final

1,974

Published on

Published in: Technology, Education
0 Comments
6 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total Views
1,974
On Slideshare
0
From Embeds
0
Number of Embeds
4
Actions
Shares
0
Downloads
80
Comments
0
Likes
6
Embeds 0
No embeds

No notes for slide

Transcript of "Kandroid for nhn_deview_20131013_v5_final"

  1. 1. High Performance Android App. Development 양정수 (Jeongsoo Yang) yangjeongsoo at gmail.com www.kandroid.org
  2. 2. CONTENT 1. The History of Android Performance Features 2. Performance Comparison of the Three Programming Models 3. Case Study : Performance Features of the Google Chrome Browser 4. Questionnaire : Multi-Core vs. GPU, Android vs. Chrome, and Beyond Android
  3. 3. Let’s go back to last summer. “Why will Android always lag behind iOS?” If you are a manufacturer, how would you solve this problem? What was OOOOOOO’s Approach? 1. The Optimization of SoC, Android Platform, and Built-in Apps 2. Belief that this was Apple’s approach to success
  4. 4. The history of Android Performance Features • Android alpha (at least two internal releases) • Android beta (5 Nov. 2007) – SDK : Java VM vs. Dalvik VM • Android first commercial release (23 Sep. 2008) • AOSP (21 Oct. 2008) – Zygote : Preload & Prelink (ASLR) • Cupcake (27 Apr. 2009) – NDK & Stable native API • Froyo (20 May 2010) – JIT (Just-in-time compilation) • Jingerbread (6 Dec. 2010) – StrictMode & NativeActivity • Honeycomb (22 Feb. 2011) – GPUI, SMP, and RenderScript • JellyBean (27 Jun. 2012) - Project Butter (Jank Buster)
  5. 5. Fast & Smooth - Jelly Bean and Project Butter Source : http://www.youtube.com/watch?v=V5E5revikUU
  6. 6. Facebook Android Development : A Scrolling Performance Story - Dec 5, 2012 Their Android Performance Challenges • • • • • • • Why Android stutter more? Measure Improvement Garbage Collection Memory View Optimization Main Thread User Perception Source : http://velocity.oreilly.com.cn/2012/ppts/Facebook-Android-Performance-OReilly-Velocity-Beijing-Dec-2012.pdf
  7. 7. The World of List View Tuesday, June 1, 2010, Google I/O FPS 60 50 40 30 20 10 0 Dumb Recycling views ViewHolder Source : https://dl.google.com/googleio/2010/android-world-of-listview-android.pdf
  8. 8. Memory and Performance March 29, 2013, 11th Kandroid Conference Event (AdapterView) Invalidate Measurement A Adapter • getView() Async Drawable Bitmap Decoding Storage Network I/O B • If an AdapterView has many children, Dumb part A is as important as part B. Layout Draw Recycle View Holder • If the AdapterView has few children, part B becomes a bottleneck. • Bitmap decoding is responsible. Source : http://www.kandroid.org/board/data/board/conference/file_in_body/1/511th_kandroidconf_memory_and_performance.pdf
  9. 9. What lessons can we learn from history? 1. Always Measure • Before beginning optimization, ensure the problem requires solving. 2. Terminology used for Android Performance Features • Bitmap Allocation • Layer, DisplayList, DisplayList Property • Input Latency • FPS, VSync
  10. 10. CONTENT 1. The History of Android Performance Features 2. Performance Comparison of the Three Programming Models 3. Case Study : Performance Features of the Google Chrome Browser 4. Questionnaire : Multi-Core vs. GPU, Android vs. Chrome, and Beyond Android
  11. 11. Comparison and Analysis of the Three Programming Models in Google Android (2012, Intel) • What are the Three Programming Models ? • Working Flow Comparison • Execution Model Comparison • Performance Difference and Analysis • Differences in Development and Deployment • Conclusion & Unified Programming Model Source : http://people.apache.org/~xli/papers/applc2012-android-programming-models.pdf
  12. 12. What are the Three Programming Models? 2008 2009 M AOSP Branch SDK (API Level) NDK (Revision) RenderScript android.support. v8.renderscript 1 2010 C D E F 23 45 6 7 8 1 2 34 2011 GH 2012 I 9 10 13 1415 5 6 7 2014 2013 J 16 8 17 18 9
  13. 13. Experiment setup : Balls
  14. 14. SDK : Workflow & Execution Model Android Runtime Android SDK JDK Input Source Program Java Compiler Bytecode (class File) dx utility Bytecode (dex File) Dalvik VM Output public static long sumArray(int[] arr) { long sum = 0; For (int i : arr) { sum += i; } return sum; } 000b: 000d: 000f: 0012: 0013: 0015: 0016: 0018: 0019: 001b: 001c: 001d: 001e: 0021: iload 05 iload 04 if_icmpge 0024 aload_3 iload 05 iaload istore 06 lload_1 iload 06 i2l ladd lstore_1 iinc 05, #+01 goto 000b 0007: 0009: 000b: 000c: 000d: if-ge v0, v2, 0010 aget v1, v8, v0 int-to-long v5, v1 add-long/2addr v3, v5 add-int/lit8 v0, v0, #int 1 000f: goto 0007
  15. 15. SDK : Workflow & Execution Model TLS Activity Thread Queue Thread Pool H handleMessage() Looper execute() ViewRootImpl handleMessage() Message Queue • onPreExecute() • onProgressUpdate() • onPostExecute • doInBackground() AsyncTask
  16. 16. NDK : Workflow & Execution Model A PPLICATIONS A PPLICATIONS HelloAndroid ActivityThread Receiver H Looper Handle Message() ViewRoot RUNTIME JNI Surface Manager FreeType SSL Libc Dalvik Virtual Machine Media Framework SGL L INUX K ERNEL Handle Message() L IBRARIES RUNTIME Core Libraries Custom Library OpenGL|ES ViewRoot Message Queue View L IBRARIES Handle Message() Custom 구현 Activity Handle Message() H Looper Service Provider Message Queue ActivityThread SQLite WebKit NativeActivity Custom Library Core Libraries Surface Manager JNI OpenGL|ES FreeType SGL SSL Libc Dalvik Virtual Machine Media Framework L INUX K ERNEL SQLite WebKit
  17. 17. RenderScript : Workflow & Execution Model App Java Sources App Java Sources Reflected Layer (C99) helloworld.rs Native Layer (RenderScript) llvmrs-cc ScriptC_ helloworld .java ScriptField_ xxxxxxxxx .java helloworld.bc Native Layer (LLVM Code)
  18. 18. RenderScript : Workflow & Execution Model Framework Layer App Java App Java App Java Sources Sources Sources Dalvik JIT Compiler Multicore CPUs Reflected Layer ScriptC_ helloworld .java GPUs/DSPs libbcc helloworld.bc Native Layer (LLVM Code) APK file LLVM based Jit compiler System lib. .bc files
  19. 19. Performance Analysis : Multiple Worker Thread 70 60 50 SDK 40 SDK-MT 30 NDK NDK-MT 20 10 0 200 300 400 500 600 700 800 900 Source : http://people.apache.org/~xli/papers/applc2012-android-programming-models.pdf 1000
  20. 20. Performance Analysis : Runtime design diff. 70 60 50 40 SDK-MT NDK-MT 30 Renderscript 20 10 0 200 300 400 500 600 700 800 900 1000 Source : http://people.apache.org/~xli/papers/applc2012-android-programming-models.pdf
  21. 21. Current Issues & Unified Programming Model 2 Class Programmability Sub Class SDK NDK + RS X X X 3 Library Extensibility O Strong Typing and Verification O X O O Portability Security RS O Memory Management NDK △ O O 3 X X X Vector Type X △ O O Thread Pool O △ O O OpenGLES Performance O O O X O 1 1. Is it possible to support vector type without changing the JNI implementation? 2. Why did Google make RS separate from NDK? 3. Are Memory Management and Strong Typing critical issues?
  22. 22. Current Issues & Unified Programming Model GDK : What is GDK? Hooray! We done the GDK building system. This building system is independent on NDK. It builds what is should (bitcodes), and then transfer the control to NDK building system, doing the remaining building. This code is still ugly. Need cleanup. gdk git commit id : edde771d8940a6f1b00fd68bcca1486b575e6d9e Author : Nowar Gu <nowar100@gmail.com>
  23. 23. GDK : hello-llvm Sample Code Android-portable.mk LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE := hello_llvm LOCAL_CFLAGS := -D NUM=7788 LOCAL_SRC_FILES := hello_llvm.c test.cpp LOCAL_C_INCLUDES := jni/test-include include $(BUILD_BITCODE) include $(CLEAR_VARS) LOCAL_MODULE := test2 LOCAL_SRC_FILES := test2.c include $(BUILD_BITCODE) Build Command $ cd ~/android-4.1.1_r1/gdk/samples/hello-llvm/jni $ export OUT=~/android-4.1.1_r1/out/target/product/generic $ ../../../gdk-build --ndk-root=~/android-ndk-r8b
  24. 24. $ ../../../gdk-build --ndk-root=/home/jsyang/android-ndk-r8b Compile Bitcode : hello_llvm <= hello_llvm.c Compile++ Bitcode: hello_llvm <= test.cpp BitcodeLibrary : libhello_llvm.bc Install BCLib : libhello_llvm.bc => res/raw/libhello_llvm.bc Compile Bitcode : test2 <= test2.c BitcodeLibrary : libtest2.bc Install BCLib : libtest2.bc => res/raw/libtest2.bc Gdbserver Gdbsetup Gdbserver Gdbsetup : [arm-linux-androideabi-4.6] libs/armeabi/gdbserver : libs/armeabi/gdb.setup : [arm-linux-androideabi-4.6] libs/armeabi-v7a/gdbserver : libs/armeabi-v7a/gdb.setup Compile thumb : hello_llvm <= hello_llvm.c Compile++ thumb : hello_llvm <= test.cpp StaticLibrary : libstdc++.a SharedLibrary : libhello_llvm.so Install : libhello_llvm.so => libs/armeabi/libhello_llvm.so Compile thumb : hello_llvm <= hello_llvm.c Compile++ thumb : hello_llvm <= test.cpp StaticLibrary : libstdc++.a SharedLibrary : libhello_llvm.so Install : libhello_llvm.so => libs/armeabi-v7a/libhello_llvm.so
  25. 25. Google I/O 2013 : Game Development Env. An Introduction to Play Game Services Game Services In Practice
  26. 26. CONTENT 1. The History of Android Performance Features 2. Performance Comparison of the Three Programming Models 3. Case Study : Performance Features of the Google Chrome Browser 4. Questionnaire : Multi-Core vs. GPU, Android vs. Chrome, and Beyond Android
  27. 27. Google I/O 2012 Keynote Android vs. Chrome
  28. 28. Google I/O 2013 Keynote Sundar Pichai (SVP, Android, Chrome & Apps)
  29. 29. Performance Features of the Google Chrome Browser • Why did Google Develop Chrome? • Chrome’s Multi-process Architecture on Android • Chrome’s Hardware Acceleration on Android • Chrome’s Networking on Android • Improved VSync scheduling for Chrome on Android
  30. 30. Why did Google Develop Chrome? Chromium Chrome browser : uses multiple processes ! Chromium safer Sandbox the web app’s process faster Separate threads for separate web apps blink v8 more stable Chromium OS Fast rendering engine, small footprint Out-of-Process iframes Optimized JS engine, many opportunities Separate address spaces for separate web apps
  31. 31. Chrome’s Multi-process Architecture on Android Source : https://sites.google.com/a/chromium.org/dev/developers/design-documents/multi-process-architecture
  32. 32. Chrome’s Multi-process Architecture on Android Browser Process Main Thread (UI) I/O Thread Render Process IPC Main Thread Render Thread android:process=":sandboxed_process0" android:isolatedProcess="true“ android:process=":privileged_process2" android:isolatedProcess="false" android:isolatedProcess If set to true, this service will run under a special process that is isolated from the rest of the system and has no permissions of its own. The only communication with it is through the Service API (binding and starting).
  33. 33. Chrome’s Hardware Acceleration on Android Software Rendering Architecture Render Process Shared Memory HWND Bitmap WebKit / Skia Brower Process IPC Source : http://www.chromium.org/developers/design-documents/gpu-accelerated-compositing-in-chrome
  34. 34. Chrome’s Hardware Acceleration on Android Compositing with the GPU process Browser Process HWND Shared Memory Render Process Commands GPU Process (server) WebKit / Skia Bitmaps & Arrays Compositor Context Compositor GL/D3D IPC Source : http://www.chromium.org/developers/design-documents/gpu-accelerated-compositing-in-chrome
  35. 35. Chrome’s Hardware Acceleration on Android Compositing with the GPU process
  36. 36. Chrome’s Hardware Acceleration on Android Compositing with the GPU Thread USER u0_a94 u0_a94 u0_a94 u0_a94 u0_a94 u0_a94 u0_a94 u0_a94 u0_a94 u0_a94 u0_a94 ... u0_a94 ... u0_i50 PID PPID 24458 125 24462 24458 24463 24458 24464 24458 24465 24458 24466 24458 24467 24458 24468 24458 24469 24458 24470 24458 24472 24458 NAME org.chromium.content_shll_apk GC Signal Catcher JDWP Compiler ReferenceQueueD FinalizerDaemon FinalizerWatchd Binder_1 Binder_2 AsyncTask #1 Browser Process GPU Thread (server) Compositor Context GL/D3D 24486 24458 ntent_shell_apk 24526 125 org.chromium.content_shel_apk:sandboxed_process1
  37. 37. Chrome’s Hardware Acceleration on Android systrace, chrome://gpu
  38. 38. Improved VSync Scheduling on Android Improved vsync scheduling for Chrome on Android - Author: skyostil@ • Motivation • Improved vsync scheduling • Vsync notification message • Triggering vsync based on input • Case studies • Conclusion Source : https://docs.google.com/a/chromium.org/document/d/16822du6DLKDZ1vQVNWI3gDVYoSqCSezgEmWZ0arvkP8/edit
  39. 39. Google I/O 2012 : For Butter or Worse - VSync VSync Drawing without VSync 0 VSync 1 1 1 2 3 CPU 3 3 Display GPU 4 2 2 3 4 3 1 1 1 3 2 0 VSync 2 2 1 Drawing with VSync VSync 4 4 Source : http://commondatastorage.googleapis.com/io2012/presentations/live%20to%20website/109.pdf 4 Display GPU CPU
  40. 40. Improved VSync Scheduling on Android Old Architecture System VSync Browser Process internal timer’s tick Render Process
  41. 41. Improved VSync Scheduling on Android Old Architecture ~3.2ms System VSync internal timer’s tick Browser Process Render Process
  42. 42. Improved VSync Scheduling on Android Old Architecture and Problems Source : https://docs.google.com/a/chromium.org/document/d/16822du6DLKDZ1vQVNWI3gDVYoSqCSezgEmWZ0arvkP8/edit
  43. 43. Improved VSync Scheduling on Android New Architecture ~3.2ms System VSync internal timer’s tick Browser Process Render Process
  44. 44. Improved VSync Scheduling on Android New Architecture : Improvement and Problem Source : https://docs.google.com/a/chromium.org/document/d/16822du6DLKDZ1vQVNWI3gDVYoSqCSezgEmWZ0arvkP8/edit
  45. 45. Improved VSync Scheduling on Android New Architecture : Improvement and Limit Conclusion This document describes improvements to vsync scheduling which allows Chrome on Android to generally respond to scroll gestures within a single vsync interval. These improvements apply to regular page scrolling, while lowering the latency of main thread and JavaScript-driven updates are left as future work. Source : https://docs.google.com/a/chromium.org/document/d/16822du6DLKDZ1vQVNWI3gDVYoSqCSezgEmWZ0arvkP8/edit
  46. 46. What lessons can we learn from Chrome? 1. On a GUI system, a scheduler for input and drawing is the most important . 2. If you review Chrome technology in this perspective, you can find valuable documents. 3. This is one document that is recommended. https://docs.google.com/document/d/1LUFA8MDpJcDHE0_L2EHvrcwqOMJhzl5dqb0AlBSqHOY/edit
  47. 47. CONTENT 1. The History of Android Performance Features 2. Performance Comparison of the Three Programming Models 3. Case Study : Performance Features of the Google Chrome Browser 4. Questionnaire : Multi-Core vs. GPU, Android vs. Chrome, and Beyond Android
  48. 48. Multi-Core vs. GPU ~12GB/s ISP 70GFLOPs LPDDR3 GPU CPU DSP ~20GFLOPs Dark Silicon and the End of Multicore Scaling http://falsedoor.com/doc/ISCA11.pdf GreenDroid: An Architecture for the Dark Silicon Age http://darksilicon.org/papers/taylor-aspdac-final-2012.pdf
  49. 49. Android vs. Chrome We have two options: The first is maintaining the status quo, the other is merging the two platforms. Status Quo • Android : Phone, Tablet, Google TV, Car • Chromium : Chrome Brower, Chrome OS Merged State • Android-centric Merger • Chrome-centric Merger • Alternate Merger
  50. 50. Android vs. Chrome For Android-centric merger to succeed, we must answer one question: “Is it possible to build chrome via Android Infrastructure?” For Chrome-centric merger to succeed, we must answer a different question: “Is it possible to run Android Apps in the Chrome?” Do you have any alternate courses?
  51. 51. Beyond Android With the current market saturation, is it possible to create a new platform? • B2G, Tizen, LG Web OS, Ubuntu Mobile The successful development of a new platform could lead to advances. Nevertheless, it would be just one more in an already saturated market. So, we must streamline the market and focus on cross-platform compatibility with the status quo. • Web-based (e.g. PhoneGap) • Native-based (e.g. Cocos2d-x) • VM-based (e.g. Mono)
  52. 52. CONTENT 1. The History of Android Performance Features 2. Performance Comparison of the Three 3. 4. Programming Models Case Study : Performance Features of the Google Chrome Browser Questionnaire : Multi-Core vs. GPU, Android vs. Chrome, and Beyond Android 지금까지 경청해 주셔서 감사합니다. 질문 있으시면 해 주세요.
  1. A particular slide catching your eye?

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

×