JVM – DVM – ART

ماشین مجازی جاوا (JVM)

یک ماشین مجازی جاوا (JVM) یک ماشین مجازی است که کامپیوتر را قادر می سازد تا برنامه های جاوا و همچنین برنامه های نوشته شده به زبان های دیگر و کامپایل شده به جاوا بایت کد را اجرا کند. مشخصات JVM  که توصیف کننده موارد مورد نیاز JVM برای اجرا است به طور کامل و با جزئیات مشخص شده است. داشتن یک مشخصه، قابلیت سازگاری برنامه های جاوا را در پیاده سازی های مختلف تضمین می کند، به طوری که توسعه دهندگان برنامه با استفاده از مجموعه توسعه جاوا (JDK) دیگر نگران ویژگی های سخت افزاری پلت فرم نیستند.

هنگامی که هر برنامه جاوا کامپایل می شود، ما بایت کد دریافت می کنیم.JVM  یک ماشین مجازی است (یک ماشین مجازی یک برنامه کاربردی است که به عنوان یک سیستم عامل عمل می کند) که می تواند این bytecode را اجرا کند. نمودار زیر نشان می دهد که چگونه یک برنامه جاوا کامپایل می شود:

 

ماشین مجازی Dalvik (DVM)

Dalvik  یک ماشین مجازی است که به طور خاص برای اندروید طراحی شده است و درابتدا توسط Dan Bornstein  نوشته شد. ماشین مجازی جاوا (JVM) دارای عملکرد بالایی است و مدیریت حافظه را عالی فراهم می کند. اما باید برای دستگاه های تلفن همراه بهینه سازی می شد. ماشین مجازی Dalvik  یک ماشین مجازی اندروید است که برای دستگاه تلفن همراه و با در نظر گرفتن محدودیت آن ها، بهینه شده است.

یکی از این محدودیت ها، محدود بودن عمر باتری است و دیگری اندازه دستگاه های تلفن همراه است که همواره کاهش می یابد. دالویک ساخته شده است تا به این محدودیت ها پاسخ دهد. Dalvik  به عنوان یک ماشین مجازی مبتنی بر رجیستری طراحی شده است که برای تراشه های مبتنی برمعماری ARM مناسب است. ARM  تمایل دارد که خیلی خنک تر از معماری معروف Intel x86  باشد. ARM  باتری کمتری مصرف می کند و نسبت به تراشه های x86 گرمای کمتری تولید می کند. ماشین مجازی استاندارد جاوا ، مبتنی بر پشته، و بیشتر برای رایانه های شخصی و سرور های امروزی مناسب است.

محدودیت دیگری که در مورد دستگاه های تلفن همراه وجود دارد، اندازه دستگاه و به تبع آن حافظه دستگاه است. در هنگام نمونه سازی از یک شی ، ماشین مجازی استاندارد جاوا، فایل کلاس را برای آن شیء در دیسک قرار می دهد و سپس آن را در RAM بارگذاری می کند. این منطقی است  زیرا که دیسک بر روی یک رایانه معمولی یا سرور، مکانیکی است، در نتیجه  با سرعت نسبتا کم تری در مقایسه با RAM ، آن را می خواند و می نویسد. از سوی دیگر، دستگاه های تلفن همراه از دیسک های سخت استفاده نمی کنند و به حافظه حالت جامد (solid state memory) برای RAM  و همچنین دیسک ذخیره سازی اش متکی است. برای به حداقل رساندن دو برابر شدن محدودیت حافظه در دسترس، دالویک فایل های کلاس را مستقیما بر روی حافظه، با اشاره به محل آن است، بارگذاری می کند و تنها مواردی که تغییر می کنند را با استفاده از الگوریتم copy-on-write، دوباره کپی می کند. این شیوه علاوه بر بالا بردن سرعت خواندن و نوشتن کمک می کند تا حافظه کمتری استفاده شود.

Copy-on-write (CoW یا COW) ، که گاهی اوقات به عنوان implicit sharing یا shadowing هم نامیده می شود، یک روش مدیریت منابع است که در برنامه های کامپیوتری استفاده می شود تا به صورت کارآمد عملیات “تکثیر” یا “کپی” را بر روی  منابع قابل تغییر انجام دهد. اگر یک منبع تکثیر شود اما تغییر نکند، ایجاد یک منبع جدید ضروری نیست و منبع را می توان بین کپی و اصلی به اشتراک گذاشت ولی در صورت ایجاد تغییرات باید یک کپی ایجاد شود. با به اشتراک گذاری منابع در زمانی که تغییرات ایجاد نمی شود، می توان به طور قابل توجهی مصرف منابع را کاهش داد.

همچنین، هر برنامه اندرویدی در فرآیند خود اجرا می شود تا sandboxing یک برنامه کاربردی که پایه و اساس مدل امنیتی اندروید  است، فراهم شود. این بدان معنی است که در هر لحظه از زمان، دستگاه اندرویدی شما ممکن است چندین ماشین مجازی دالویک را در حافظه داشته باشد. برای به حداقل رساندن مصرف حافظه، دالویک، کتابخانه های سیستم را به جای ایجاد یک کپی برای هر نمونه، به اشتراک می گذارد.

در جاوا، سورس کد های نوشته شده به زبان جاوا، به استفاده از کامپایلر جاوا به جاوا بایت کد کامپایل شده و در ماشین مجازی جاوا اجرا می شود اما در اندروید مراحل کمی متفاوت است. در اندروید اگرچه سورس کدها به زبان جاوا نوشته و به جاوا بایت کد تبدیل می شوند اما با ماشین مجازی جاوا اجرا نمی شوند و سپس دوباره کامپایل می شوند. این بایت کدهای جاوا بوسیله کامپایلر Dex به دالویک بایت کد تبدیل می شوند و بر روی ماشین مجازی دالویک اجرا می شوند. دالویک بایت کد در مقایسه با جاوا بایت کد برای محیط هایی با حافظه کم و همچنین قدرت پردازش کم بسیار مناسب تر است.

تصویر زیر نحوه تبدیل جاوا بایت کد (.class) به دالویک بایت کد (.dex) را نشان می دهد:

یکی دیگر از علت های جاگزین شدن ماشین مجازی جاوا با ماشین مجازی دالویک مجوز است. اگرچه زبان جاوا، ابزار های جاوا و همچنین کتابخانه های جاوا رایگان هستند اما ماشین مجازی جاوا اینطور نیست. این موضوع یک مشکل در سال 2005 بود تا اینکه کار بر بروی دالویک آغاز شد و امروزه جایگزین های منبع بازی چون پروژه های OpenJDK و Apache Harmony نیز به عنوان جایگزین برای ماشین مجازی جاوا وجود دارند. اگرچه اندروید از Apache Harmony برای کتابخانه های جاوای خود استفاده می کند، اما به دالویک برای اجرای کد متکی است.

با توسعه یک دستگاه مجازی واقعا منبع باز، اندروید بار دیگر پلت فرم کاملی را فراهم می کند که دیگران تشویق می شوند تا برای انواع دستگاه های مختلف، بدون نیاز به نگرانی در مورد مجوز، از آن استفاده کنند.

تصویر زیر مقایسه بین جاوا استاندارد (در سمت چپ) و اندروید با استفاده از دالویک ( در سمت راست) را نشان می دهد:

ممکن است این سوال در ذهن ایجاد شود که چرا سورس کد جاوا مستقیما به دالویک بایت کد کامپایل نمی شود؟ در پاسخ به این سوال می توان گفت که دلایل خوبی برای گام های اضافه وجود داشت. در سال 2005 هنگامیکه کار بر روی دالویک آغاز شد، زبان جاوا مکررا تغییر کرد اما جاوا بایت کد کمابیش بدون تغییر ماند. بنابراین تیم اندروید تصمیم گرفتند که دالویک را بر پایه جاوا بایت کد به جای سورس کد جاوا قرار دهند. از کاربردهای این کار این است که برنامه های اندرویدی می توانند به زبان های دیگری نوشته شوند و به جاوا بایت کد کامپایل شوند. برای مثال، شما می توانید از زبان هایی مانند روبی و یا پایتون برای نوشتن سورس کد برنامه تان استفاده کنید. امروزه شاهد برنامه ها و فریم ورک هایی هستیم که از زبان های دیگر پشتیبانی می کنند و توسعه اندروید را برای مخاطبان و توسعه دهندگان جذاب تر می کنند.

موردی دیگری که باید به توجه کرد این است که جاوای مورد استفاده در اندروید یک مجموعه ی غیر استاندارد از کلاس های جاوا است. جاوا به طور معمول در نسخه های Java Standard Edition که توسعه برنامه های ساده و ابتدایی دسکتاپ مورد استفاده قرار می گیرد، Java Enterprise Edition (به طور مخفف J2EE یا JavaEE) که برای توسعه برنامه های تجاری مورد استفاده قرار می گیرد و  Java Micro Edition (به طور مخفف J2ME یا JavaME) که برای توسعه برنامه های موبایل استفاده می شود، وجود دارد. مجموعه کتابخانه های جاوای موجود در اندروید بیشتر به Java Standard Edition نزدیک است و بزرگترین تفاوت آن ها جایگزینی کتابخانه های رابط کاربری جاوا با کتابخانه های رابط کاربری مخصوص اندروید است. البته اندروید ویژگی های جدیدی نیز به ویژگی های استاندارد جاوا می افزاید. بنابراین، شما بیشتر کتابخانه جاوا مورد علاقه خود را به علاوه بسیاری از موارد جدید در اختیار دارید.

 

Zygote

یکی از اولین فرآیند هایی که در زمان بوت یک دستگاه اندرویدی آغاز می شود، فرآیند Zygote است. Zygote، به نوبه خود، مسئولیت ایجاد سرویس های اضافی و بارگذاری کتابخانه های مورد استفاده توسط فریم ورک اندروید را بر عهده دارد.  فرایند Zygote  سپس به عنوان لودر برای هر فرآیند Dalvik با ایجاد یک کپی از خود ، عمل می کند. این بهینه سازی مانع تکرار فرآیند گران بارگذاری فریم ورک اندروید و وابستگی های آن در زمان شروع فرآیندهای دالویک (که شامل برنامه ها می شود) می شود. در نتیجه، کتابخانه های هسته، کلاس های اصلی و ساختارهای مربوطه در مورد ماشین مجازی دالویک، مشترک هستند و این یک فرصت جالب برای حمله را ایجاد می کند.

وظیفه دوم Zygote شروع فرآیند system server  است. این فرایند شامل تمام سرویس های اصلی مانند activity manager، power manager، backup service، telephony manager، view system، notification manager و … که تحت شناسه system در اندروید (AID) و با سطح دسترسی بالاتری  اجرا می شوند، می باشد و هنگامی که اجرا  می شود تمام سریس های فریم ورک اندروید را شروع می کند.

پس از شروع اولیه، Zygote  دسترسی به کتابخانه برای سایر فرایندهای Dalvik از طریق RPC (Remote Procedure Call) و  IPC (inter-process communication) را فراهم می کند. این مکانیسمی است که در آن فرآیندهایی که میزبان کامپاننت های یک برنامه اندروید هستند، آغاز می شوند.

 

Android Runtime (ART)

Runtime Android (ART)  به هسته لینوکس برای عملکردهای اساسی مانند threading  و مدیریت سطح پایین حافظه وابسته است. از اندروید نسخه 5.0 Lollipop ، دالویک که مبتنی بر JIT کامپایل بود با Android Runtime  (ART) جایگزین شد، در حالی که فرمت بایت کدش هنوز به عنوان یک فرمت استفاده می شود. اندروید 7.0 نیز یک کامپایلر JIT را با استفاده از code profiling  به ART اندروید اضافه کرده است که به طور مداوم عملکرد برنامه های اندروید را در زمان اجرا افزایش می دهد.

نسخه های پیشین اندروید ازکامپایل مبتنی بر JIT ( just-in-time ) همراه با دالویک استفاده می شد. در JIT، غالبا عملیات اجرا شده شناسایی شده و به صورت پویا به کد ماشین native  کامپایل می شدند.

برخلاف دالویک، ART ازکامپایل مبتنی بر  AOT ( ahead-of-time )  استفاده می کند. AOT تمام برنامه ها را در زمان نصب شان به کدهای ماشین native کامپایل می کند. با حذف Dalvik و کامپایل کردن به صورت JIT ، ART بهره وری را افزایش و مصرف برق را کاهش می دهد که این باعث افزایش عمر باتری در دستگاه های تلفن همراه می شود. ART  در عین حال که از DEX بایت کد ها به عنوان ورودی استفاده می کند ( همانند Dalvik )، اجرای سریع تر برنامه های کاربردی، بهبود تخصیص حافظه و مکانیسم های جمع آوری زباله  (GC)، ویژگی های جدید اشکال زدایی نرم افزارها و غیره را به ارمغان می آورد.

استفاده از ART به طور خودکار زمان نصب یک برنامه را افزایش می دهد اما مزیت بزرگ آن، حذف دالویک و کامپایل مبتنی بر JIT و به تبع آن افزایش کارایی و کاهش مصرف باتری است. ART از ابزاری به نام dex2oat استفاده می کند که فایل های DEX را به عنوان ورودی گرفته و یک برنامه کامپایل شده ی قابل اجرا برای دستگاه مورد نظر تولید می کند. تصویر چگونگی کامپایل شدن کدهای ART را نشان می دهد:

اگر برنامه شما به خوبی روی ART اجرا می شود، روی Dalvik نیز کار می کند، اما عکس آن ممکن است درست نباشد.

 

Just In Time  (JIT)

با کامپایلر JIT دالویک، هر دفعه که برنامه ای اجرا می شود، JIT به صورت پویا یک بخش از دالویک بایت کد را به کدهای ماشین ترجمه می کند. هرچه اجرا جلو تر می رود، بایت کدهای بیشتری کامپایل و cache می شوند. چون JIT فقط بخشی از یک کد را کامپایل می کند، فضای کمتری از حافظه دستگاه استفاده می شود.

 

Ahead Of Time (AOT)

ART به یک کامپایلر Ahead-of-Time مجهز است. این کامپایلر در زمان نصب یک برنامه به صورت استاتیک DEX بایت کدها را به زبان ماشین ترجمه و حافظه دستگاه ذخیره می کند.این رویداد یک بار و فقط زمانی که یک برنامه نصب می شود، اتفاق می افتد. در این روش با اینکه ART به زمان بیشتری برای کامپایل نیاز دارد و پس نصب یک برنامه کمی بیشتر(نسبت به روش just-in-time) از فضای حافظه استفاده می شود اما کدها سریع تر اجرا می شوند. زیرا ART مستقیما کدهای ماشین را اجرا می کند واین به اندازه کامپایل کردن کدها به روش just-in-time در دالویک CPU را درگیر نمی کند. در نتیجه با استفاده کمتر از CPU، باتری کمتری نیز مصرف می شود.

 

گردآورنده و مترجم : مریم مکاریان خراسانی

 

منابع:

  • Mobile Application Penetration Testing,Copyright © 2016,Vijay Kumar Velu, Published by Packt Publishing Ltd.
  • https://en.wikipedia.org/wiki/Java_virtual_machine
  • https://en.wikipedia.org/wiki/Copy-on-write
  • https://android.jlelse.eu/closer-look-at-android-runtime-dvm-vs-art-1dc5240c3924