लेन-देन गाइड

परिचय

अनसैंडबॉक्स की गई C/C++ लाइब्रेरी का इस्तेमाल करते समय, लिंकर यह पक्का करता है कि कंपाइल करने के बाद सभी ज़रूरी फ़ंक्शन उपलब्ध हों. इसलिए, इस बात की चिंता करने की ज़रूरत नहीं है कि रनटाइम के दौरान कोई एपीआई कॉल फ़ेल हो सकता है या नहीं.

हालांकि, सैंडबॉक्स की गई लाइब्रेरी का इस्तेमाल करते समय, लाइब्रेरी का एक्ज़ीक्यूशन एक अलग प्रोसेस में होता है. एपीआई कॉल के फ़ेल होने पर, आरपीसी लेयर पर कॉल पास करने से जुड़ी सभी तरह की समस्याओं की जांच करना ज़रूरी है. कभी-कभी, आरपीसी लेयर की गड़बड़ियां काम की नहीं होती हैं. उदाहरण के लिए, एक साथ कई कार्रवाइयां करते समय और जब सैंडबॉक्स को अभी-अभी रीस्टार्ट किया गया हो.

हालांकि, ऊपर बताई गई वजहों से, सैंडबॉक्स किए गए एपीआई कॉल की रिटर्न वैल्यू की नियमित तौर पर गड़बड़ी की जांच को बढ़ाना ज़रूरी है. इसमें यह जांच करना भी शामिल है कि आरपीसी लेयर पर कोई गड़बड़ी तो नहीं हुई है. इसलिए, सभी लाइब्रेरी फ़ंक्शन के प्रोटोटाइप, T के बजाय ::sapi::StatusOr<T> दिखाते हैं. अगर लाइब्रेरी फ़ंक्शन को कॉल नहीं किया जा सका (जैसे, सैंडबॉक्स के नियमों का उल्लंघन होने की वजह से), तो रिटर्न वैल्यू में हुई गड़बड़ी के बारे में जानकारी शामिल होगी.

आरपीसी लेयर की गड़बड़ियों को ठीक करने का मतलब है कि सैंडबॉक्स की गई लाइब्रेरी को किए गए हर कॉल के बाद, SAPI की आरपीसी लेयर की एक और जांच की जाती है. ऐसी खास स्थितियों से निपटने के लिए, SAPI, SAPI लेन-देन मॉड्यूल (transaction.h) उपलब्ध कराता है. इस मॉड्यूल में ::sapi::Transaction क्लास होती है. यह पक्का करता है कि सैंडबॉक्स की गई लाइब्रेरी को किए गए सभी फ़ंक्शन कॉल, आरपीसी-लेवल की किसी भी समस्या के बिना पूरे हो गए हों या कोई काम की गड़बड़ी वापस आ गई हो.

SAPI लेन-देन

SAPI, होस्ट कोड को सैंडबॉक्स की गई लाइब्रेरी से अलग करता है. साथ ही, कॉल करने वाले को डेटा प्रोसेस करने के अनुरोध को फिर से शुरू करने या रद्द करने की सुविधा देता है. SAPI Transaction, एक कदम आगे बढ़कर काम करता है. यह उन प्रोसेस को अपने-आप दोहराता है जो पूरी नहीं हो सकीं.

SAPI लेन-देन का इस्तेमाल दो अलग-अलग तरीकों से किया जा सकता है: सीधे तौर पर ::sapi::Transaction से इनहेरिट करके या ::sapi::BasicTransaction को पास किए गए फ़ंक्शन पॉइंटर का इस्तेमाल करके.

SAPI लेन-देन को इन तीन फ़ंक्शन को ओवरराइड करके तय किया जाता है:

SAPI लेन-देन के तरीके
::sapi::Transaction::Init() यह किसी सामान्य C/C++ लाइब्रेरी के इनिशियलाइज़ेशन मेथड को कॉल करने जैसा है. इस तरीके को सैंडबॉक्स की गई लाइब्रेरी में हर लेन-देन के दौरान सिर्फ़ एक बार कॉल किया जाता है. हालांकि, अगर लेन-देन को फिर से शुरू किया जाता है, तो इसे दोबारा कॉल किया जा सकता है. रीस्टार्ट होने पर, इस तरीके को फिर से कॉल किया जाता है. इससे कोई फ़र्क़ नहीं पड़ता कि इससे पहले कितनी बार रीस्टार्ट किया गया है.
::sapi::Transaction::Main() इस तरीके को, ::sapi::Transaction::Run() को किए गए हर कॉल के लिए कॉल किया जाता है.
::sapi::Transaction::Finish() यह किसी सामान्य C/C++ लाइब्रेरी के क्लीन-अप तरीके को कॉल करने जैसा है. इस तरीके को SAPI लेन-देन ऑब्जेक्ट को हटाने के दौरान सिर्फ़ एक बार कॉल किया जाता है.

लाइब्रेरी का सामान्य इस्तेमाल

सैंडबॉक्स की गई लाइब्रेरी के बिना किसी प्रोजेक्ट में, लाइब्रेरी को मैनेज करने का सामान्य तरीका कुछ ऐसा दिखता है:

LibInit();
while (data = NextDataToProcess()) {
  result += LibProcessData(data);
}
LibClose();

लाइब्रेरी को शुरू किया जाता है. इसके बाद, लाइब्रेरी के एक्सपोर्ट किए गए फ़ंक्शन का इस्तेमाल किया जाता है. आखिर में, एनवायरमेंट को क्लीन-अप करने के लिए, एंड/क्लोज़ फ़ंक्शन को कॉल किया जाता है.

सैंडबॉक्स की गई लाइब्रेरी का इस्तेमाल

सैंडबॉक्स की गई लाइब्रेरी वाले प्रोजेक्ट में, Normal Library Use का कोड, कॉलबैक के साथ लेन-देन का इस्तेमाल करते समय, इस कोड स्निपेट में बदल जाता है:

// Overwrite the Init method, passed to BasicTransaction initialization
::absl::Status Init(::sapi::Sandbox* sandbox) {
  // Instantiate the SAPI Object
  LibraryAPI lib(sandbox);
  // Instantiate the Sandboxed Library
  SAPI_RETURN_IF_ERROR(lib.LibInit());
  return ::absl::OkStatus();
}

// Overwrite the Finish method, passed to BasicTransaction initialization
::absl::Status Finish(::sapi::Sandbox *sandbox) {
  // Instantiate the SAPI Object
  LibraryAPI lib(sandbox);
  // Clean-up sandboxed library instance
  SAPI_RETURN_IF_ERROR(lib.LibClose());
  return ::absl::OkStatus();
}

// Wrapper function to process data, passed to Run method call
::absl::Status HandleData(::sapi::Sandbox *sandbox, Data data_to_process,
                           Result *out) {
  // Instantiate the SAPI Object
  LibraryAPI lib(sandbox);
  // Call the sandboxed function LibProcessData
  SAPI_ASSIGN_OR_RETURN(*out, lib.LibProcessData(data_to_process));
  return ::absl::OkStatus();
}

void Handle() {
  // Use SAPI Transactions by passing function pointers to ::sapi::BasicTransaction
  ::sapi::BasicTransaction transaction(Init, Finish);
  while (data = NextDataToProcess()) {
    ::sandbox2::Result result;
    // call the ::sapi::Transaction::Run() method
    transaction.Run(HandleData, data, &result);
    // ...
  }
  // ...
}

लेन-देन की क्लास, यह पक्का करती है कि handle_data इनवॉकेशन के दौरान कोई गड़बड़ी होने पर, लाइब्रेरी को फिर से शुरू किया जाए. इसके बारे में ज़्यादा जानकारी अगले सेक्शन में दी गई है.

लेन-देन फिर से शुरू होना

अगर SAPI लेन-देन के तरीकों (ऊपर दी गई टेबल देखें) को लागू करते समय, सैंडबॉक्स की गई लाइब्रेरी के एपीआई कॉल से कोई गड़बड़ी होती है, तो लेन-देन फिर से शुरू हो जाएगा. रीस्टार्ट की डिफ़ॉल्ट संख्या, transaction.h में kDefaultRetryCnt से तय होती है.

यहां गड़बड़ियों के कुछ ऐसे उदाहरण दिए गए हैं जिनकी वजह से, डिवाइस को रीस्टार्ट करना पड़ सकता है:

  • सैंडबॉक्स के उल्लंघन की समस्या हुई
  • सैंडबॉक्स की गई प्रोसेस क्रैश हो गई
  • लाइब्रेरी में हुई गड़बड़ी की वजह से, सैंडबॉक्स किए गए फ़ंक्शन ने गड़बड़ी का कोड दिखाया

रीस्टार्ट करने की प्रोसेस में, सामान्य Init() और Main() फ़्लो का पालन किया जाता है. अगर ::sapi::Transaction::Run() तरीके को बार-बार कॉल करने पर गड़बड़ियां मिलती हैं, तो पूरा तरीका कॉल करने वाले को गड़बड़ी दिखाता है

सैंडबॉक्स या आरपीसी से जुड़ी गड़बड़ी ठीक करना

अपने-आप जनरेट होने वाला Sandboxed Library interface, C/C++ लाइब्रेरी के ओरिजनल फ़ंक्शन प्रोटोटाइप के जितना हो सके उतना करीब होता है. हालांकि, सैंडबॉक्स की गई लाइब्रेरी को किसी भी सैंडबॉक्स या आरपीसी से जुड़ी गड़बड़ियों के बारे में सूचना देनी होगी.

इसके लिए, सैंडबॉक्स किए गए फ़ंक्शन की रिटर्न वैल्यू को सीधे तौर पर दिखाने के बजाय, ::sapi::StatusOr<T> रिटर्न टाइप (या void दिखाने वाले फ़ंक्शन के लिए ::sapi::Status) का इस्तेमाल किया जाता है.

SAPI, SAPI Status ऑब्जेक्ट की जांच करने और उस पर प्रतिक्रिया देने के लिए, कुछ सुविधाजनक मैक्रो भी उपलब्ध कराता है. इन मैक्रो को status_macro.h हेडर फ़ाइल में तय किया गया है.

नीचे दिया गया कोड स्निपेट, sum example से लिया गया है. इसमें SAPI स्टेटस और मैक्रो के इस्तेमाल के बारे में बताया गया है:

// Instead of void, use ::sapi::Status
::sapi::Status SumTransaction::Main() {
  // Instantiate the SAPI Object
  SumApi f(sandbox());

  // ::sapi::StatusOr<int> sum(int a, int b)
  SAPI_ASSIGN_OR_RETURN(int v, f.sum(1000, 337));
  // ...

  // ::sapi::Status sums(sapi::v::Ptr* params)
  SumParams params;
  params.mutable_data()->a = 1111;
  params.mutable_data()->b = 222;
  params.mutable_data()->ret = 0;
  SAPI_RETURN_IF_ERROR(f.sums(params.PtrBoth()));
  // ...
  // Gets symbol address and prints its value
  int *ssaddr;
  SAPI_RETURN_IF_ERROR(sandbox()->Symbol(
      "sumsymbol", reinterpret_cast<void**>(&ssaddr)));
  ::sapi::v::Int sumsymbol;
  sumsymbol.SetRemote(ssaddr);
  SAPI_RETURN_IF_ERROR(sandbox()->TransferFromSandboxee(&sumsymbol));
  // ...
  return ::sapi::OkStatus();
}

सैंडबॉक्स रीस्टार्ट

सैंडबॉक्स की गई कई लाइब्रेरी, उपयोगकर्ता के संवेदनशील इनपुट को मैनेज करती हैं. अगर किसी समय सैंडबॉक्स की गई लाइब्रेरी खराब हो जाती है और रन के बीच डेटा सेव करती है, तो इस संवेदनशील डेटा को खतरा होता है. उदाहरण के लिए, अगर Imagemagick लाइब्रेरी का सैंडबॉक्स किया गया वर्शन, पिछली बार के रन की तस्वीरें भेजना शुरू कर देता है.

इस तरह की समस्या से बचने के लिए, सैंडबॉक्स का इस्तेमाल कई बार नहीं किया जाना चाहिए. सैंडबॉक्स का दोबारा इस्तेमाल रोकने के लिए, होस्ट कोड, सैंडबॉक्स वाली लाइब्रेरी की प्रोसेस को फिर से शुरू कर सकता है. इसके लिए, SAPI ट्रांज़ैक्शन का इस्तेमाल करते समय ::sapi::Sandbox::Restart() या ::sapi::Transaction::Restart() का इस्तेमाल किया जा सकता है.

रीस्टार्ट करने पर, सैंडबॉक्स की गई लाइब्रेरी प्रोसेस का कोई भी रेफ़रंस अमान्य हो जाएगा. इसका मतलब है कि पास किए गए फ़ाइल डिस्क्रिप्टर या मेमोरी का बंटवारा अब मौजूद नहीं रहेगा.