অ্যান্ড্রয়েড এবিআই

বিভিন্ন অ্যান্ড্রয়েড ডিভাইস ভিন্ন ভিন্ন সিপিইউ ব্যবহার করে, যেগুলো আবার ভিন্ন ভিন্ন ইন্সট্রাকশন সেট সমর্থন করে। সিপিইউ এবং ইন্সট্রাকশন সেটের প্রতিটি সমন্বয়ের নিজস্ব অ্যাপ্লিকেশন বাইনারি ইন্টারফেস (এবিআই) থাকে। একটি এবিআই-তে নিম্নলিখিত তথ্যগুলো অন্তর্ভুক্ত থাকে:

  • সিপিইউ নির্দেশাবলী সেট (এবং এর সম্প্রসারণ) যা ব্যবহার করা যেতে পারে।
  • The endianness of memory stores and loads at runtime. Android is always little-endian.
  • অ্যাপ্লিকেশন এবং সিস্টেমের মধ্যে ডেটা আদান-প্রদানের প্রচলিত নিয়ম, যার মধ্যে অ্যালাইনমেন্ট সংক্রান্ত সীমাবদ্ধতাও অন্তর্ভুক্ত, এবং সিস্টেম কীভাবে ফাংশন কল করার সময় স্ট্যাক ও রেজিস্টার ব্যবহার করে।
  • প্রোগ্রাম এবং শেয়ার্ড লাইব্রেরির মতো এক্সিকিউটেবল বাইনারিগুলোর ফরম্যাট এবং সেগুলো যে ধরনের কন্টেন্ট সমর্থন করে। অ্যান্ড্রয়েড সবসময় ELF ব্যবহার করে। আরও তথ্যের জন্য, ELF সিস্টেম V অ্যাপ্লিকেশন বাইনারি ইন্টারফেস দেখুন।
  • C++ নামগুলো কীভাবে ম্যাঙ্গল করা হয়। আরও তথ্যের জন্য, Generic/Itanium C++ ABI দেখুন।

এই পৃষ্ঠায় NDK দ্বারা সমর্থিত ABI-গুলোর তালিকা এবং প্রতিটি ABI কীভাবে কাজ করে সে সম্পর্কে তথ্য দেওয়া হয়েছে।

ABI বলতে প্ল্যাটফর্ম দ্বারা সমর্থিত নেটিভ API-কেও বোঝাতে পারে। ৩২-বিট সিস্টেমকে প্রভাবিত করে এমন ধরনের ABI সমস্যাগুলির তালিকার জন্য, ৩২-বিট ABI বাগ দেখুন।

সমর্থিত ABI

সারণি ১. এবিআই এবং সমর্থিত নির্দেশাবলী সেটসমূহ।

এবিআই সমর্থিত নির্দেশাবলী সেট নোট
armeabi-v7a
  • আরমেবি
  • থাম্ব-২
  • নিয়ন
  • ARMv5/v6 ডিভাইসের সাথে সামঞ্জস্যপূর্ণ নয়।
    arm64-v8a
  • AArch64
  • শুধুমাত্র Armv8.0 এর জন্য।
    x86
  • x86 (IA-32)
  • এমএমএক্স
  • এসএসই/২/৩
  • এসএসএসই৩
  • MOVBE বা SSE4-এর জন্য কোনো সমর্থন নেই।
    x86_64
  • x86-64
  • এমএমএক্স
  • এসএসই/২/৩
  • এসএসএসই৩
  • SSE4.1, 4.2
  • POPCNT
  • CMPXCHG16B
  • LAHF-SAHF
  • সম্পূর্ণ x86-64-v2 .

    দ্রষ্টব্য: ঐতিহাসিকভাবে NDK, ARMv5 (armeabi) এবং ৩২-বিট ও ৬৪-বিট MIPS সমর্থন করত, কিন্তু NDK r17 থেকে এই ABI-গুলোর সমর্থন সরিয়ে দেওয়া হয়েছে।

    armeabi-v7a

    এই ABI-টি ৩২-বিট ARM সিপিইউ-এর জন্য। এর মধ্যে Thumb-2 এবং Neon অন্তর্ভুক্ত।

    ABI-এর যে অংশগুলো অ্যান্ড্রয়েড-নির্দিষ্ট নয়, সে সম্পর্কে তথ্যের জন্য ARM আর্কিটেকচারের জন্য অ্যাপ্লিকেশন বাইনারি ইন্টারফেস (ABI) দেখুন।

    আপনি যদি ndk-build-এর জন্য আপনার Android.mk তে LOCAL_ARM_MODE অথবা CMake কনফিগার করার সময় ANDROID_ARM_MODE ব্যবহার না করেন, তাহলে NDK-এর বিল্ড সিস্টেমগুলো ডিফল্টভাবে Thumb-2 কোড তৈরি করে।

    নিওনের ইতিহাস সম্পর্কে আরও তথ্যের জন্য, নিওন সাপোর্ট দেখুন।

    ঐতিহাসিক কারণে, এই ABI-টি -mfloat-abi=softfp ব্যবহার করে, যার ফলে ফাংশন কল করার সময় সমস্ত float ভ্যালু ইন্টিজার রেজিস্টারে এবং সমস্ত double ভ্যালু ইন্টিজার রেজিস্টার পেয়ারে পাস করা হয়। নামটি এমন হলেও, এটি শুধুমাত্র ফ্লোটিং পয়েন্ট কলিং কনভেনশনকে প্রভাবিত করে: কম্পাইলার গাণিতিক কাজের জন্য হার্ডওয়্যার ফ্লোটিং পয়েন্ট ইনস্ট্রাকশনই ব্যবহার করবে।

    এই ABI একটি ৬৪-বিট long double ব্যবহার করে ( IEEE binary64, যা double এর সমান)।

    arm64-v8a

    এই ABI-টি ৬৪-বিট ARM সিপিইউ-এর জন্য।

    ABI-এর যে অংশগুলো অ্যান্ড্রয়েড-নির্দিষ্ট নয়, সেগুলোর সম্পূর্ণ বিবরণের জন্য Arm-এর 'Learn the Architecture' দেখুন। Arm তাদের '64-bit Android Development' বইটিতে পোর্টিং সংক্রান্ত কিছু পরামর্শও প্রদান করে।

    আপনি অ্যাডভান্সড সিমডি এক্সটেনশনের সুবিধা নিতে সি এবং সি++ কোডে নিওন ইনট্রিনসিক ব্যবহার করতে পারেন। Armv8-A-এর জন্য নিওন প্রোগ্রামারস গাইডটিতে নিওন ইনট্রিনসিক এবং সাধারণভাবে নিওন প্রোগ্রামিং সম্পর্কে আরও তথ্য রয়েছে।

    অ্যান্ড্রয়েডে, প্ল্যাটফর্ম-নির্দিষ্ট x18 রেজিস্টারটি ShadowCallStack-এর জন্য সংরক্ষিত থাকে এবং আপনার কোড দ্বারা এটি স্পর্শ করা উচিত নয়। Clang-এর বর্তমান সংস্করণগুলি অ্যান্ড্রয়েডে ডিফল্টরূপে -ffixed-x18 অপশনটি ব্যবহার করে, তাই আপনার হাতে লেখা অ্যাসেম্বলার (বা খুব পুরানো কম্পাইলার) না থাকলে, এই বিষয়ে আপনার চিন্তা করার প্রয়োজন নেই।

    এই ABI একটি 128-বিট long double ( IEEE বাইনারি128 ) ব্যবহার করে।

    x86

    This ABI is for CPUs supporting the instruction set commonly known as "x86", "i386", or "IA-32".

    অ্যান্ড্রয়েডের ABI-তে মূল ইন্সট্রাকশন সেটের পাশাপাশি MMX , SSE , SSE2 , SSE3 এবং SSSE3 এক্সটেনশনগুলো অন্তর্ভুক্ত রয়েছে।

    ABI-তে MOVBE বা SSE4-এর কোনো সংস্করণের মতো অন্য কোনো ঐচ্ছিক IA-32 ইন্সট্রাকশন সেট এক্সটেনশন অন্তর্ভুক্ত নেই। তবে, আপনি এই এক্সটেনশনগুলো ব্যবহার করতে পারবেন, যদি আপনি রানটাইম ফিচার-প্রোবিং ব্যবহার করে সেগুলোকে সক্রিয় করেন এবং যেসব ডিভাইস এগুলো সমর্থন করে না, তাদের জন্য ফলব্যাকের ব্যবস্থা রাখেন।

    এনডিকে টুলচেইন একটি ফাংশন কলের আগে ১৬-বাইট স্ট্যাক অ্যালাইনমেন্ট ধরে নেয়। ডিফল্ট টুল এবং অপশনগুলো এই নিয়মটি প্রয়োগ করে। আপনি যদি অ্যাসেম্বলি কোড লেখেন, তবে আপনাকে অবশ্যই স্ট্যাক অ্যালাইনমেন্ট বজায় রাখতে হবে এবং নিশ্চিত করতে হবে যে অন্যান্য কম্পাইলারও এই নিয়মটি মেনে চলে।

    আরও বিস্তারিত তথ্যের জন্য নিম্নলিখিত নথিগুলি দেখুন:

    এই ABI একটি ৬৪-বিটের long double ব্যবহার করে ( IEEE binary64-এ যা double সমতুল্য, এবং এটি বহুল প্রচলিত ৮০-বিটের শুধুমাত্র ইন্টেল-এর জন্য ব্যবহৃত long double নয়)।

    x86_64

    এই ABI-টি সেইসব সিপিইউ-এর জন্য, যেগুলো সাধারণত "x86-64-v2" নামে পরিচিত ইন্সট্রাকশন সেট সমর্থন করে।

    অ্যান্ড্রয়েডের ABI-তে মূল ইন্সট্রাকশন সেটের পাশাপাশি MMX , SSE , SSE2 , SSE3 , SSSE3 , SSE4.1 , SSE4.2 এবং POPCNT ইন্সট্রাকশন অন্তর্ভুক্ত রয়েছে।

    ABI-তে MOVBE, SHA, বা AVX-এর কোনো সংস্করণের মতো অন্য কোনো ঐচ্ছিক x86-64 ইন্সট্রাকশন সেট এক্সটেনশন অন্তর্ভুক্ত নেই। আপনি এই এক্সটেনশনগুলি ব্যবহার করতে পারেন, তবে শর্ত হলো আপনাকে রানটাইম ফিচার প্রোবিং ব্যবহার করে সেগুলি সক্রিয় করতে হবে এবং যে ডিভাইসগুলি সেগুলি সমর্থন করে না, তাদের জন্য ফলব্যাকের ব্যবস্থা রাখতে হবে।

    আরও বিস্তারিত তথ্যের জন্য নিম্নলিখিত নথিগুলি দেখুন:

    এই ABI একটি 128-বিট long double ( IEEE বাইনারি128 ) ব্যবহার করে।

    একটি নির্দিষ্ট ABI-এর জন্য কোড তৈরি করুন

    গ্রেডল

    Gradle (Android Studio বা কমান্ড লাইন থেকে ব্যবহৃত হোক না কেন) ডিফল্টরূপে সমস্ত অপ্রচলিত নয় এমন ABI-এর জন্য বিল্ড করে। আপনার অ্যাপ্লিকেশন যে ABI-গুলো সমর্থন করে তার সেট সীমিত করতে, abiFilters ব্যবহার করুন। উদাহরণস্বরূপ, শুধুমাত্র 64-বিট ABI-এর জন্য বিল্ড করতে, আপনার build.gradle এ নিম্নলিখিত কনফিগারেশনটি সেট করুন:

    android {
        defaultConfig {
            ndk {
                abiFilters 'arm64-v8a', 'x86_64'
            }
        }
    }
    

    এনডিকে-বিল্ড

    ndk-build ডিফল্টরূপে সমস্ত অপ্রচলিত নয় এমন ABI-এর জন্য বিল্ড তৈরি করে। আপনি আপনার Application.mk ফাইলে APP_ABI সেট করে একটি নির্দিষ্ট ABI-কে টার্গেট করতে পারেন। নিম্নলিখিত কোড স্নিপেটে APP_ABI ব্যবহারের কয়েকটি উদাহরণ দেখানো হলো:

    APP_ABI := arm64-v8a  # Target only arm64-v8a
    APP_ABI := all  # Target all ABIs, including those that are deprecated.
    APP_ABI := armeabi-v7a x86_64  # Target only armeabi-v7a and x86_64.
    

    APP_ABI জন্য আপনি যে মানগুলি নির্দিষ্ট করতে পারেন সে সম্পর্কে আরও তথ্যের জন্য, Application.mk দেখুন।

    CMake

    CMake ব্যবহার করে একবারে একটিমাত্র ABI-এর জন্য বিল্ড করা যায় এবং আপনাকে অবশ্যই আপনার ABI স্পষ্টভাবে উল্লেখ করতে হবে। এটি করার জন্য ANDROID_ABI ভেরিয়েবলটি ব্যবহার করতে হয়, যা অবশ্যই কমান্ড লাইনে উল্লেখ করতে হবে (এটি আপনার CMakeLists.txt ফাইলে সেট করা যাবে না)। উদাহরণস্বরূপ:

    $ cmake -DANDROID_ABI=arm64-v8a ...
    $ cmake -DANDROID_ABI=armeabi-v7a ...
    $ cmake -DANDROID_ABI=x86 ...
    $ cmake -DANDROID_ABI=x86_64 ...
    

    NDK দিয়ে বিল্ড করার জন্য CMake-এ যে অন্যান্য ফ্ল্যাগগুলো অবশ্যই পাস করতে হবে, সেগুলোর জন্য CMake গাইড দেখুন।

    বিল্ড সিস্টেমের ডিফল্ট আচরণ হলো প্রতিটি ABI-এর বাইনারিগুলোকে একটিমাত্র APK-তে অন্তর্ভুক্ত করা, যা ফ্যাট APK নামেও পরিচিত। একটি ফ্যাট APK, শুধুমাত্র একটি ABI-এর বাইনারি ধারণকারী APK-এর চেয়ে আকারে উল্লেখযোগ্যভাবে বড় হয়; এর বিনিময়ে বৃহত্তর সামঞ্জস্যতা পাওয়া যায়, কিন্তু তার জন্য APK-টির আকার বড় হয়ে যায়। সর্বোচ্চ ডিভাইস সামঞ্জস্যতা বজায় রেখে আপনার APK-গুলোর আকার কমানোর জন্য অ্যাপ বান্ডেল (App Bundles) অথবা এপিকে স্প্লিট (APK Splits) ব্যবহার করার জন্য দৃঢ়ভাবে সুপারিশ করা হয়।

    ইনস্টলেশনের সময়, প্যাকেজ ম্যানেজার টার্গেট ডিভাইসের জন্য শুধুমাত্র সবচেয়ে উপযুক্ত মেশিন কোডটি আনপ্যাক করে। বিস্তারিত জানতে, ‘ইনস্টলের সময় নেটিভ কোডের স্বয়ংক্রিয় নিষ্কাশন’ দেখুন।

    অ্যান্ড্রয়েড প্ল্যাটফর্মে ABI ব্যবস্থাপনা

    এই অংশে অ্যান্ড্রয়েড প্ল্যাটফর্ম কীভাবে APK-তে নেটিভ কোড পরিচালনা করে, সে সম্পর্কে বিস্তারিত আলোচনা করা হয়েছে।

    অ্যাপ প্যাকেজে নেটিভ কোড

    প্লে স্টোর এবং প্যাকেজ ম্যানেজার উভয়ই আশা করে যে, APK-এর ভেতরের ফাইলপাথগুলোতে NDK দ্বারা তৈরি লাইব্রেরিগুলো নিম্নলিখিত প্যাটার্ন অনুযায়ী থাকবে:

    /lib/<abi>/lib<name>.so
    

    এখানে, <abi> হলো Supported ABIs-এর অধীনে তালিকাভুক্ত ABI নামগুলোর মধ্যে একটি, এবং <name> হলো লাইব্রেরির নাম, যা আপনি Android.mk ফাইলের LOCAL_MODULE ভেরিয়েবলের জন্য সংজ্ঞায়িত করেছেন। যেহেতু APK ফাইলগুলো কেবল জিপ ফাইল, তাই সেগুলো খুলে শেয়ার্ড নেটিভ লাইব্রেরিগুলো নিজ নিজ স্থানে আছে কিনা তা নিশ্চিত করা খুবই সহজ।

    If the system does not find the native shared libraries where it expects them, it cannot use them. In such a case, the app itself has to copy the libraries over, and then perform dlopen() .

    একটি ফ্যাট APK-তে, প্রতিটি লাইব্রেরি এমন একটি ডিরেক্টরির অধীনে থাকে যার নাম সংশ্লিষ্ট ABI-এর সাথে মেলে। উদাহরণস্বরূপ, একটি ফ্যাট APK-তে থাকতে পারে:

    /lib/armeabi-v7a/libfoo.so
    /lib/arm64-v8a/libfoo.so
    /lib/x86/libfoo.so
    /lib/x86_64/libfoo.so
    

    অ্যান্ড্রয়েড প্ল্যাটফর্ম ABI সমর্থন

    অ্যান্ড্রয়েড সিস্টেম রানটাইমে জানে যে এটি কোন ABI(গুলি) সমর্থন করে, কারণ বিল্ড-নির্দিষ্ট সিস্টেম প্রোপার্টিগুলি তা নির্দেশ করে:

    • ডিভাইসটির প্রাথমিক ABI, যা সিস্টেম ইমেজটিতে ব্যবহৃত মেশিন কোডের অনুরূপ।
    • ঐচ্ছিকভাবে, সেকেন্ডারি ABI-গুলো, যা সিস্টেম ইমেজ দ্বারা সমর্থিত অন্যান্য ABI-এর অনুরূপ।

    এই প্রক্রিয়াটি নিশ্চিত করে যে সিস্টেমটি ইনস্টলেশনের সময় প্যাকেজ থেকে সেরা মেশিন কোডটি নিষ্কাশন করে।

    আপনি একটি নির্দিষ্ট ABI-এর জন্য apk জোর করে ইনস্টল করতে পারেন। একাধিক ABI সমর্থন করে এমন ডিভাইসে পরীক্ষার জন্য এটি কার্যকর হতে পারে। নিম্নলিখিত কমান্ডটি ব্যবহার করুন:

    adb install --abi abi-identifier path_to_apk
    

    ইনস্টলের সময় নেটিভ কোডের স্বয়ংক্রিয় নিষ্কাশন

    অ্যাপ্লিকেশন ইনস্টল করার সময়, প্যাকেজ ম্যানেজার সার্ভিসটি APK ফাইলটি স্ক্যান করে এবং নিম্নলিখিত ধরনের শেয়ার্ড লাইব্রেরিগুলো খুঁজে দেখে:

    lib/<primary-abi>/lib<name>.so
    

    যদি কোনোটি খুঁজে না পাওয়া যায়, এবং আপনি একটি দ্বিতীয় ABI নির্ধারণ করে থাকেন, তাহলে পরিষেবাটি নিম্নলিখিত ধরনের শেয়ার্ড লাইব্রেরিগুলির জন্য স্ক্যান করে:

    lib/<secondary-abi>/lib<name>.so
    

    প্যাকেজ ম্যানেজার যখন তার কাঙ্ক্ষিত লাইব্রেরিগুলো খুঁজে পায়, তখন সেগুলোকে অ্যাপ্লিকেশনটির নেটিভ লাইব্রেরি ডিরেক্টরির ( <nativeLibraryDir>/ ) অধীনে থাকা /lib/lib<name>.so ফাইলে কপি করে। নিচের কোড স্নিপেটগুলো nativeLibraryDir খুঁজে বের করে:

    কোটলিন

    import android.content.pm.PackageInfo
    import android.content.pm.ApplicationInfo
    import android.content.pm.PackageManager
    ...
    val ainfo = this.applicationContext.packageManager.getApplicationInfo(
            "com.domain.app",
            PackageManager.GET_SHARED_LIBRARY_FILES
    )
    Log.v(TAG, "native library dir ${ainfo.nativeLibraryDir}")

    জাভা

    import android.content.pm.PackageInfo;
    import android.content.pm.ApplicationInfo;
    import android.content.pm.PackageManager;
    ...
    ApplicationInfo ainfo = this.getApplicationContext().getPackageManager().getApplicationInfo
    (
        "com.domain.app",
        PackageManager.GET_SHARED_LIBRARY_FILES
    );
    Log.v( TAG, "native library dir " + ainfo.nativeLibraryDir );

    যদি কোনো শেয়ার্ড-অবজেক্ট ফাইল একেবারেই না থাকে, তাহলে অ্যাপ্লিকেশনটি বিল্ড ও ইন্সটল হলেও রানটাইমে ক্র্যাশ করে।

    ARMv9: C/C++ এর জন্য PAC এবং BTI সক্রিয় করা

    PAC/BTI সক্রিয় করলে কিছু অ্যাটাক ভেক্টরের বিরুদ্ধে সুরক্ষা পাওয়া যাবে। PAC একটি ফাংশনের প্রোলগে রিটার্ন অ্যাড্রেসকে ক্রিপ্টোগ্রাফিকভাবে স্বাক্ষর করে এবং এপিলগে সেটি এখনও সঠিকভাবে স্বাক্ষরিত আছে কিনা তা পরীক্ষা করে রিটার্ন অ্যাড্রেসকে সুরক্ষিত রাখে। BTI আপনার কোডের যথেচ্ছ স্থানে জাম্প করা প্রতিরোধ করে, কারণ এর জন্য প্রতিটি ব্রাঞ্চ টার্গেটকে একটি বিশেষ ইন্সট্রাকশন হতে হয়, যা প্রসেসরকে সেখানে ল্যান্ড করার অনুমতি দেওয়া ছাড়া আর কিছুই করে না।

    অ্যান্ড্রয়েড PAC/BTI নির্দেশাবলী ব্যবহার করে, যা পুরোনো প্রসেসরগুলিতে কোনো কাজ করে না, কারণ সেগুলো নতুন নির্দেশাবলী সমর্থন করে না। শুধুমাত্র ARMv9 ডিভাইসগুলিতেই PAC/BTI সুরক্ষা থাকবে, কিন্তু আপনি ARMv8 ডিভাইসেও একই কোড চালাতে পারবেন: আপনার লাইব্রেরির একাধিক সংস্করণের কোনো প্রয়োজন নেই। এমনকি ARMv9 ডিভাইসেও, PAC/BTI শুধুমাত্র ৬৪-বিট কোডের ক্ষেত্রেই প্রযোজ্য।

    PAC/BTI সক্রিয় করলে কোডের আকার সামান্য বৃদ্ধি পাবে, সাধারণত ১%।

    PAC/BTI কোন কোন অ্যাটাক ভেক্টরকে লক্ষ্য করে এবং এই সুরক্ষা ব্যবস্থা কীভাবে কাজ করে, তার বিস্তারিত ব্যাখ্যার জন্য Arm-এর 'Learn the architecture - Providing protection for complex software' ( PDF ) দেখুন।

    বিল্ড পরিবর্তন

    এনডিকে-বিল্ড

    আপনার Android.mk-এর প্রতিটি মডিউলে LOCAL_BRANCH_PROTECTION := standard সেট করুন।

    CMake

    আপনার CMakeLists.txt-এর প্রতিটি টার্গেটের জন্য target_compile_options($TARGET PRIVATE -mbranch-protection=standard) ব্যবহার করুন।

    অন্যান্য বিল্ড সিস্টেম

    আপনার কোড কম্পাইল করার সময় -mbranch-protection=standard ফ্ল্যাগটি ব্যবহার করুন। এই ফ্ল্যাগটি শুধুমাত্র arm64-v8a ABI-এর জন্য কম্পাইল করার সময় কাজ করে। লিঙ্কিং করার সময় এই ফ্ল্যাগটি ব্যবহার করার প্রয়োজন নেই।

    সমস্যা সমাধান

    PAC/BTI-এর কম্পাইলার সাপোর্টে কোনো সমস্যা আছে বলে আমাদের জানা নেই, কিন্তু:

    • লিঙ্কিং করার সময় BTI এবং নন-BTI কোড যেন মিশে না যায়, সেদিকে খেয়াল রাখবেন, কারণ এর ফলে এমন একটি লাইব্রেরি তৈরি হয় যেটিতে BTI সুরক্ষা সক্রিয় থাকে না। আপনার তৈরি হওয়া লাইব্রেরিতে BTI নোটটি আছে কি না, তা পরীক্ষা করার জন্য আপনি llvm-readelf ব্যবহার করতে পারেন।
    $ llvm-readelf --notes LIBRARY.so
    [...]
    Displaying notes found in: .note.gnu.property
      Owner                Data size    Description
      GNU                  0x00000010   NT_GNU_PROPERTY_TYPE_0 (property note)
        Properties:    aarch64 feature: BTI, PAC
    [...]
    $
    
    • OpenSSL-এর পুরোনো সংস্করণগুলিতে (1.1.1i-এর আগের) হাতে লেখা অ্যাসেম্বলারে একটি বাগ রয়েছে, যার কারণে PAC ব্যর্থ হয়। বর্তমান OpenSSL-এ আপগ্রেড করুন।

    • কিছু অ্যাপ ডিআরএম সিস্টেমের পুরোনো সংস্করণ এমন কোড তৈরি করে যা পিএসি/বিটিআই-এর শর্তাবলী লঙ্ঘন করে। আপনি যদি অ্যাপ ডিআরএম ব্যবহার করেন এবং পিএসি/বিটিআই সক্রিয় করার সময় কোনো সমস্যা দেখতে পান, তাহলে একটি সংশোধিত সংস্করণের জন্য আপনার ডিআরএম বিক্রেতার সাথে যোগাযোগ করুন।