Patent Publication Number: US-11663321-B2

Title: Hybrid managed and unmanaged data model

Description:
BACKGROUND 
     Field of the Disclosure 
     This disclosure relates generally to the execution of computer applications, and more particularly to systems and methods for executing applications containing both managed code and unmanaged code. 
     Description of the Related Art 
     Modern computer application development languages fall into two broad categories, languages supporting unmanaged code, such as C and C++, and languages supporting managed code, such as Java™, C#, R, Python and Ruby. Unmanaged code may suffer from various well known issues, for example memory access vulnerabilities such as buffer overflows, which when not caught may result in undefined behaviors and security vulnerabilities. Existing approaches to mitigate these risks include inserting runtime checks in applications to catch violations and coding errors but these checks are inherently imprecise in the sense that a missing check might lead to an undetected security vulnerability. 
     Managed code, on the other hand, uses a combination of language features and the assistance of a runtime environment for the application to mitigate risks generally associated with unmanaged code. Applications developed using languages and toolsets supporting managed code are therefore considered memory-safe. 
     It is impractical, however, to simply replace unmanaged code with managed code in order to receive such memory safety benefits as an enormous body of software has been developed using unmanaged code. On the other hand, unmanaged code may be compiled with improved tools such that the resulting application uses a runtime environment similar, or identical, to that of managed code. Using this approach, data objects defined by the unmanaged code are translated and stored using managed memory allocations. This approach results in sandboxed execution of the unmanaged code, and with sandboxed execution memory accesses in the unmanaged code receive the benefits of memory safety. 
     Sandboxed execution, however, by virtue of utilizing the runtime environment of managed code, is generally unable to interact with unmanaged code that has been compiled to execute natively rather than in sandboxed mode, as the memory model for the two execution environments is entirely different. 
     Disclosed herein is a hybrid execution environment for applications that utilize both managed code and unmanaged code. In this hybrid environment, in-memory data objects can be in one of two states: managed or unmanaged. When allocating an object from managed code, objects are allocated in the Managed State with information recorded describing the layout of the object in the Unmanaged State. Within unmanaged code using sandboxed execution, all accesses to the objects are memory-safe. However, if an object in Managed State is passed to non-sandboxed native code, it is first transformed to the Unmanaged State. Once transformed, the original managed object is rewritten as a simple pointer to the unmanaged memory. This native pointer can then be passed to non-sandboxed code. Existing references to the managed object, including from sandboxed code, then have to access the object contents via this pointer. 
     SUMMARY 
     Methods, techniques and systems implementing an application execution engine for executing an application including both managed code and unmanaged code are described, with the managed code providing memory safety for accesses to objects in memory and the unmanaged code providing no such memory safety. During execution of the application and responsive to a request from managed code of the application, the application execution engine creates an object in a Managed State by allocating memory for an object in a managed pool, creating a managed layout for the object in the managed memory, generating an unmanaged data layout template and making the object accessible to managed code in a Managed State providing memory safety. Responsive to a requirement for unmanaged code to access the created object accessible in the Managed State, the application execution engine transforms the object to be accessible in an Unmanaged State, the transformation including allocating unmanaged memory for the object in an unmanaged pool, copying data from managed memory to unmanaged memory according to a unmanaged data layout template, making the managed memory available for reuse and using an address of the unmanaged memory to access the object in the Unmanaged State. 
    
    
     
       BRIEF DESCRIPTION OF THE DRAWINGS 
         FIG.  1    is a block diagram illustrating a system implementing an application that includes both managed and unmanaged code. 
         FIG.  2    is a flow diagram illustrating one embodiment of a method for building an application that includes both managed and unmanaged code. 
         FIG.  3    is a block diagram illustrating a managed data template and a corresponding unmanaged data template for an object according to some embodiments. 
         FIG.  4 A-F  are flow diagrams illustrating one embodiment of a method for allocating and managing a data object for an application that includes both managed and unmanaged code. 
         FIG.  5    is a block diagram illustrating one embodiment of a computing system that is configured to execute an application that includes both managed and unmanaged code, as described herein. 
     
    
    
     While the disclosure is described herein by way of example for several embodiments and illustrative drawings, those skilled in the art will recognize that the disclosure is not limited to embodiments or drawings described. It should be understood that the drawings and detailed description hereto are not intended to limit the disclosure to the particular form disclosed, but on the contrary, the disclosure is to cover all modifications, equivalents and alternatives falling within the spirit and scope as defined by the appended claims. Any headings used herein are for organizational purposes only and are not meant to limit the scope of the description or the claims. As used herein, the word “may” is used in a permissive sense (i.e., meaning having the potential to) rather than the mandatory sense (i.e. meaning must). Similarly, the words “include”, “including”, and “includes” mean including, but not limited to. 
     Various units, circuits, or other components may be described as “configured to” perform a task or tasks. In such contexts, “configured to” is a broad recitation of structure generally meaning “having circuitry that” performs the task or tasks during operation. As such, the unit/circuit/component can be configured to perform the task even when the unit/circuit/component is not currently on. In general, the circuitry that forms the structure corresponding to “configured to” may include hardware circuits. Similarly, various units/circuits/components may be described as performing a task or tasks, for convenience in the description. Such descriptions should be interpreted as including the phrase “configured to.” Reciting a unit/circuit/component that is configured to perform one or more tasks is expressly intended not to invoke 35 U.S.C. § 112(f) interpretation for that unit/circuit/component. 
     This specification includes references to “one embodiment” or “an embodiment.” The appearances of the phrases “in one embodiment” or “in an embodiment” do not necessarily refer to the same embodiment, although embodiments that include any combination of the features are generally contemplated, unless expressly disclaimed herein. Particular features, structures, or characteristics may be combined in any suitable manner consistent with this disclosure. 
     DETAILED DESCRIPTION OF EMBODIMENTS 
     Modern applications are frequently implemented using managed code and managed data models. This approach allows for a combination of source language and runtime features that enhance memory safety and application security. A wide variety of source languages, including for example the Java™ programming language, have been designed specifically to provide these safety features, but it is also possible to adapt source code written in unmanaged languages, such as C and C++, to execute in a managed environment using managed data models. This approach offers advantages including memory safety and interoperability with managed languages like R, Python or Ruby but is not binary compatible with existing native code. 
     Disclosed herein is an application execution environment including a hybrid data model that retains the advantages of managed data models, where possible, while allowing transition to a binary-compatible representation when necessary for interoperating with natively compiled, unmanaged code. This enables development of memory-safe applications that are capable of integrating with legacy code where source for the legacy code is not available to the application developer. 
     The hybrid data model defines data layouts and access for data objects that exist in one of two states: a Managed State and an Unmanaged State. Initial allocation of an object may be performed in a Managed State and, additionally, information is kept regarding the layout of the object should it be transformed into an Unmanaged State. Source code developed in an unmanaged language, such as C or C++, and compiled to execute within a Managed Runtime, is executed as sandboxed code where data object accesses, though written to be performed as unmanaged accesses, may be performed in the Managed State and receive the benefits of memory safety. 
     If a data object in a Managed State is passed to non-sandboxed unmanaged code, it must first be transformed to an Unmanaged State. At that point, memory is allocated from an unmanaged memory pool and an unmanaged representation of the object is constructed from the state of the managed object using predetermined layout information contained in a data layout template. Such a transformation may recursively trigger other managed objects to transform to an Unmanaged State as well. The original managed object is then rewritten to include a simple address to the allocated unmanaged memory and may also include additional metadata in some embodiments. This address can then be passed to non-sandboxed unmanaged code. Subsequent references to the managed object must then occur in an Unmanaged State unless and until a reverse transformation occurs. This hybrid approach provides memory safety where possible but remains interoperable with native unmanaged code libraries where source code is unavailable. 
       FIG.  1    is a block diagram illustrating a system implementing an application execution engine that executes an application including both managed and unmanaged code. The System  100  includes one or more Processors  110  capable executing an Application  130  contained in Memory  120 , where the Application  130  may include both a Managed Runtime  140  and an Unmanaged Runtime  150 . The Managed Runtime  140  may execute within a Virtual Machine (not shown) in some embodiments and may include a Runtime Library  142  a Bytecode Executive that may further include a Bytecode Compiler  143  and Bytecode Interpreter  144  for executing the Managed Bytecode of Managed Code  160   a , as detailed further below in  FIG.  2   . In addition, the Managed Runtime  140  may include a Managed Pool  148  to support Objects  190   a  created in a Managed State. The Unmanaged Runtime  150  may include Unmanaged Code  160   b  and Unmanaged Pool  158  to support Objects  190   b  created in an Unmanaged State. 
       FIG.  2    is a block diagram illustrating a process for developing an Application  130  that includes both Managed Code  160   a  and Unmanaged Code  160   b . The source code for the application may include source code written in a managed language  210  such as Java™ or C#. The source code for the application may also include source code written in an unmanaged language  220  and  230  such as such as C or C++. Source code written in an unmanaged language may be compiled using a compiler targeting managed bytecode  240  or it may be compiled using a compiler targeting native bytecode  250  while source code written in an managed language may be compiled using a compiler targeting managed bytecode  240 . A compiler targeting native bytecode  250  produces Native Bytecode  270  which results in Unmanaged Code  160   b  within the Application  130 . A compiler targeting managed bytecode  240  produces Managed Bytecode  260  which results in Managed Code  160   a  within the Application  130 . The Managed Code  160   a  and Unmanaged Code  160   b , in combination with a Managed Runtime  140  discussed above, collectively implement the Application  130 . It should be understood that the various compilers  240  and  250  may, in some embodiments, be distinct compilers implemented as separate software development tools or applications while in other embodiments these compilers may be implemented using one or more common software development tools or applications. For example, in some embodiments source code written in an unmanaged language  220  and  230  may be compiled using compilers targeting managed bytecode  240  and unmanaged bytecode  250  respectively where these compilers are implemented within a common software development application. Similarly, in some embodiments source code written in a managed language  210  and an unmanaged language may be compiled using compilers targeting managed bytecode  240  where these compilers are implemented within a common software development application. These compilers  240  and  250  may be implemented in a variety of ways using a variety of software development tools or applications and the implementations described above are merely examples and are not intended to be limiting. 
       FIG.  3    is a block diagram illustrating a Managed Data Template  300   a  and a corresponding Unmanaged Data Template  300   b  for an Object  190  according to some embodiments. An Application  130  may create an Object  190  consisting of one or more elements including primitive elements such as bytes, integers, floating point numbers, addresses and so on. In addition, the Object  190  may also consist of other objects, arrays of objects and so on. Examples of such elements may include Integer  310 , Reference  320  and Array  330 , although objects may include any number and type of elements and the above are merely examples and are not intended to be limiting. 
     Each element of the Object  190  has a corresponding entry in the Managed Data Template  300   a  and Unmanaged Data Template  300   b . In the Managed Data Template  300   a , an element may have a corresponding type and offset into memory for the Object  190   a  allocated from the Managed Pool  148  to store the value of the element, such as in the integer Offset  311   a  and Type  312   a , array Offset  331   a  and reference Offset  321   a  and Type  322   a . In addition, the Managed Data Layout Template  300   a  may contains metadata including an object Type  302  and Size  304 . 
     An Object  190  may also contain objects or arrays of objects such as Array element  330  which has corresponding Objects  333   a  as well as Array Range metadata  334   a . The Range metadata  334   a  may contain the number of elements in the array of objects stored in the Array Objects  333   a . It should be noted that while metadata of the Array element  330  is illustrated as Array Range  334   a , additional metadata for each object in the Array Objects  333   a  may be stored as described in the managed data template of the individual objects of the Array  340 . 
     The Managed Runtime  140  may use the metadata associated with individual elements to implement memory safety. For example, the Managed Runtime  140  may use the Array Range  334   a  of Array  330  to perform bounds checking on accesses to the Array Objects  333   a  in order to detect out of range conditions that might otherwise lead to memory corruption. 
     Each element of the Object  190  may have a corresponding entry in the Unmanaged Data Template  300   b . These entries correspond to the native storage requirements of the Object  190   b  allocated in the Unmanaged Pool  158 , such as for Integer Value  313   b , Reference Value  323   b  and Array Values  333   b , as defined in the binary interface of the Unmanaged Code  160   b . These corresponding entries may include offsets into the Object  190   b , such as Integer Offset  311   b , Reference Offset  321   b  and Array Offset  331   b , as well as indicators of data types of the respective elements such as Integer Type  312   b  and Reference Type  332   b . In addition, the Unmanaged Data template  300   b  may contain Optional Metadata  308  which may contain additional information describing aspects of unmanaged data layout for the Object  190 . For example, the Optional Metadata  308  may contain information identifying the application binary interface standard supported in the unmanaged data layout or may contain information such as data alignment requirements for the object  190   b.    
     An Application  130  implementing the Object  190  may transition between managed data and unmanaged data representations of the object using templates  300   a  and  300   b . While some elements, such as Integer  310  and Reference  320 , may have values that directly correspond in the managed and unmanaged data templates, such as Integer Value  313   a  and Integer Value  313   b  as well as Reference Value  323   a  and Reference Value  323   b , other elements may not have values that directly correspond in the managed and unmanaged data templates, such as Array  330 . This is due to individual objects of the Array  330  containing both values and metadata stored in the Array Objects  333   a  in the Managed Data Template  300   a  whereas the Array Values  333   b  may store values but not store corresponding object metadata. 
     It should be understood that the various elements and metadata described above are merely examples of elements of an Object  190  and are not intended to be limiting. Indeed, a variety of metadata supporting memory safety for objects may be envisioned and the above examples are intended only to be illustrative of the need for object metadata in a managed representation of an Object  190  and the resulting differences between managed and unmanaged representations of an Object  190 . 
       FIG.  4 A-F  are flow diagrams illustrating a method for allocating and managing a data object for an application that includes both managed and unmanaged code according to some embodiments.  FIG.  4 A  is a flow diagram illustrating one embodiment of a method for creating and managing an object in an application using the hybrid data model described herein. 
     The method starts at step  400  where the Managed Runtime  140  initializes and begins execution, including execution of the Application Code  160 . The Application Code  160  then requests that an Object  190  be created in a Managed State in step  410 . This request may be made as part of initial startup of the Application Code  160  or at any time during execution of the Application  130 . Responsive to this request, the Managed Runtime  140  creates the Object  190   a  in a Managed State at step  420 . This creation is further detailed in  FIG.  4 B  below. After creation of the Object  190   a  in a Managed State, the Application  130  may access the Object  190  using Managed Code  160   a  with the benefits of memory safety. Subsequent to the creation of the Object  190   a  in a Managed State, the Application Code  160  determines in step  430  that access to the Object  190 , currently in a Managed State  190   a , is required in an Unmanaged State by Unmanaged Code  160   b . Responsive to this determination, the Managed Runtime  140  transforms the Object  190  to be accessible in an Unmanaged State in step  440 . This transformation is further detailed in  FIG.  4 C  below. After transformation of the Object  190  to an Unmanaged State, the Application  130  may access the Object  190   b  in step  460  using both Managed Code  160   a  and Unmanaged Code  160   b . Furthermore, access to the Object in a Managed State  190   a  by Managed Code  160   a  is not allowed. Subsequent to the transformation of the Object  190  to an Unmanaged State  190   b , the Application  130  performs the determined access to the Object  190  using Unmanaged Code  160   b  in step  460 . In some embodiments, after access to the Object  190  in an Unmanaged State is complete, the Object may be transformed to be accessible in a Managed State in step  470 . This transformation may occur responsive to completion of the access in an Unmanaged State in some embodiments or responsive to a request to access the Object  190  in a Managed State in other embodiments. This transformation is further detailed in  FIG.  4 E  below. In still other embodiments, once the Object  190  has been transformed to be accessible in an Unmanaged State, the Object remains accessible in an Unmanaged State and is not subsequently transformed to be accessible in a Managed State. 
       FIG.  4 B  is a flow diagram illustrating one embodiment of a method for creating an object in a Managed State such as in step  410  of  FIG.  4 A . The method starts at step  412  by allocating Managed Memory  190   a  for the Object  190  in a Managed Pool  148 . The method then generates one or more Data Layout Templates, including an Unmanaged Data Layout Template  310  for the Object  190  in step  414 . These templates may be used in transforming the Object  190  for access in an various states, such as discussed further below in  FIG.  4 C  and  FIG.  4 E , and examples of these templates are provided above in  FIG.  3   . In some embodiments, these one or more Data Layout Templates may be generated each time an object is created in a Managed State while in other embodiments, the one or more Data Layout Templates may be created only the first time an object of a given type is created with the one or more Data Layout Templates for an object of a given type reused during the creation of additional objects of the same given type. Next, the method generates a managed data layout in the allocated managed memory  190   a  for the Object  190  to enable access to the Object  190  in a Managed State, as shown in step  416 . Upon completion of step  416 , the Object  190  has been created for access in a Managed State. It should be noted that while the Data Layout Templates are shown to be generated in step  420 , this generation does not depend, nor is it a dependency of, any other steps in the method. Therefore, the generation of the Data Layout Templates may occur at any time during or prior to creation of the Object  190  in a Managed State and the example performing this generation in the sequence shown in  FIG.  4 B  is not intended to be limiting. 
       FIG.  4 C  is a flow diagram illustrating one embodiment of a method for transforming an object in a Managed State to an Unmanaged State such as in step  440  of  FIG.  4 A . The method starts at step  442  by allocating Unmanaged Memory  190   b  for the Object  190  in an Unmanaged Pool  158 . The method then copies data from Managed Memory  190   a  of the Object  190  to the Unmanaged Memory  190   b  of the Object  190  according to Unmanaged Data Layout Template  302  in step  444 . Further details of this copying step are discussed below in  FIG.  4 D . Once the data is copied, the method makes the Managed Memory  190   a  for the Object  190  available to be returned to the Managed Pool  148  in step  450 . The Object  190  is then accessible in an Unmanaged State using the location of Object  190   b  in the Unmanaged Memory  190   b  as shown in step  452 . Accesses to the Object  190  in an Unmanaged State may be performed by either Managed Code  160   a  or Unmanaged Code  160   b , but accesses to the Object  190  in a Managed State may not be performed by Managed Code  160   a  as Managed Memory  190   a  has been returned to the Managed Pool  148 . Furthermore, accesses to the Object  190  in the Unmanaged State may not benefit from the memory safety of a Managed State regardless of whether the accesses are performed by Managed Code  160   a  or Unmanaged Code  160   b.    
       FIG.  4 D  is a flow diagram illustrating one embodiment of a method for copying data from managed memory of an object to unmanaged memory of the object such as in step  444  of  FIG.  4 C . The method begins by determining if additional elements in the object need to be copied in step  448 . If additional elements exist, the method selects a next element of the object in step  445 . The selected element is checked in step  446  to determine if it is a managed object. If the element is not a managed object, data for the element is copied from the managed memory to the unmanaged memory according to the managed and unmanaged data layout templates in step  447 . If, on the other hand, the element is a managed object, the object is transformed to be accessible in the Unmanaged State in step  440  as show in  FIG.  4 C  above. In addition, an element of a managed object may reference, or may contain a reference to, another object. In some embodiments, these references may be managed objects. In these embodiments, transforming the element in step  440  may include transforming the referenced object to be accessible in an Unmanaged State. In other embodiments, copying data of the element including the reference in step  447  may include transforming the referenced object to be accessible in an Unmanaged State. The method returns to step  448  to process the next element if additional elements exist. Once no additional elements exist, the method completes. 
       FIG.  4 E  is a flow diagram illustrating one embodiment of a method for transforming an object in an Unmanaged State to a Managed State such as in step  470  of  FIG.  4 A . The method starts at step  472  by allocating Managed Memory  190   a  for the Object  190  in a Managed Pool  148 . The method then copies data from Unmanaged Memory  190   b  of the Object  190  to the Managed Memory  190   a  of the Object  190  according to a Managed Data Layout Template  300   a  in step  474 . Further details of this copying step are discussed below in  FIG.  4 F . Once the data is copied, the method releases the Unmanaged Memory  190   b  for the Object  190  back to the Unmanaged Pool  158  in step  480 . The Object  190  is then accessible in a Managed State. Accesses to the Object  190  in an Unmanaged State may not be performed by Unmanaged Code  160   b . Furthermore, accesses to the Object  190  in the Managed State benefit from the memory safety of a Managed State. 
       FIG.  4 F  is a flow diagram illustrating one embodiment of a method for copying data from unmanaged memory of an object to managed memory of the object such as in step  474  of  FIG.  4 E . The method begins by determining if additional elements in the object need to be copied in step  478 . If additional elements exist, the method selects a next element of the object in step  475 . The selected element is checked in step  476  to determine if the element is to be a managed object. If the element is not to be a managed object, data for the element is copied from the unmanaged memory to the managed memory according to the managed data layout template in step  477 . If, on the other hand, the element is to be a managed object, the element is transformed to be accessible in the Managed State in step  470  as shown in  FIG.  4 E  above. The method returns to step  478  to process the next element if additional elements exist. Once no additional elements exist, the method completes. 
     Some of the mechanisms described herein may be provided as a computer program product, or software, that may include a non-transitory, computer-readable storage medium having stored thereon instructions which may be used to program a computer system  500  (or other electronic devices) to perform a process according to various embodiments. A computer-readable storage medium may include any mechanism for storing information in a form (e.g., software, processing application) readable by a machine (e.g., a computer). The machine-readable storage medium may include, but is not limited to, magnetic storage medium (e.g., floppy diskette); optical storage medium (e.g., CD-ROM); magneto-optical storage medium; read only memory (ROM); random access memory (RAM); erasable programmable memory (e.g., EPROM and EEPROM); flash memory; electrical, or other types of medium suitable for storing program instructions. In addition, program instructions may be communicated using optical, acoustical or other form of propagated signal (e.g., carrier waves, infrared signals, digital signals, etc.) 
     In various embodiments, computer system  500  may include one or more processors  560 ; each may include multiple cores, any of which may be single- or multi-threaded. For example, multiple processor cores may be included in a single processor chip (e.g., a single processor  560 ), and multiple processor chips may be included in computer system  500 . Each of the processors  560  may include a cache or a hierarchy of caches  570 , in various embodiments. For example, each processor chip  560  may include multiple L1 caches (e.g., one per processor core) and one or more other caches (which may be shared by the processor cores on a single processor). 
     The computer system  500  may also include one or more storage devices  550  (e.g. optical storage, magnetic storage, hard drive, tape drive, solid state memory, etc.) and one or more system memories  510  (e.g., one or more of cache, SRAM, DRAM, RDRAM, EDO RAM, DDR RAM, SDRAM, Rambus RAM, EEPROM, etc.). In some embodiments, one or more of the storage device(s)  550  may be implemented as a module on a memory bus (e.g., on interconnect  540 ) that is similar in form and/or function to a single in-line memory module (SIMM) or to a dual in-line memory module (DIMM). Various embodiments may include fewer or additional components not illustrated in  FIG.  5    (e.g., video cards, audio cards, additional network interfaces, peripheral devices, a network interface such as an ATM interface, an Ethernet interface, a Frame Relay interface, etc.) 
     The one or more processors  560 , the storage device(s)  550 , and the system memory  510  may be coupled to the system interconnect  540 . One or more of the system memories  510  may contain program instructions  520  executable to implement one or more applications  522 , shared libraries  524 , and/or operating systems  526 . These program instructions  520  may be encoded in platform unmanaged binary, any interpreted language such as Java™ byte-code, or in any other language such as C/C++, the Java™ programming language, etc., or in any combination thereof. In various embodiments, applications  522 , operating system  526 , and/or shared libraries  524  may each be implemented in any of various programming languages or methods or a combination of programming languages or methods. For example, in one embodiment, operating system  526  may be based on the Java™ programming language, while in other embodiments it may be written using the C or C++ programming languages. Similarly, applications  522  may be written using the Java™ programming language or another programming language or combination of programming languages as shown in  FIG.  2    according to various embodiments. Moreover, in some embodiments, applications  522 , operating system  526 , and/shared libraries  524  may not be implemented using the same programming language or languages. For example, applications  522  may be Java™ based, while shared libraries  524  may be developed using C. 
     In conclusion, methods, techniques and systems implementing an application execution engine for executing an application including both managed code and unmanaged code are disclosed. This application execution engine includes a hybrid data model that supports accesses to data object in both a Managed State and an Unmanaged State using managed and unmanaged data layout templates for directing transitions between managed and unmanaged layouts of data objects. During execution of an application and responsive to a request from managed code, the application execution engine creates an object in a Managed State and may additionally create managed and unmanaged layouts for the object. Responsive to a requirement for unmanaged code to access the created object accessible in the Managed State, the application execution engine transforms the object to be accessible in an Unmanaged State using an unmanaged data layout template. The application execution engine thus retains the advantages of managed data models, where possible, while allowing transitions to a binary-compatible representation where necessary for interoperating with native unmanaged code, thus enabling development of memory-safe applications that are capable of integrating with legacy code where source for the legacy code is not available to the application developer.