| <html devsite> |
| <head> |
| <title>RIL Refactoring</title> |
| <meta name="project_path" value="/_project.yaml" /> |
| <meta name="book_path" value="/_book.yaml" /> |
| </head> |
| <body> |
| <!-- |
| Copyright 2017 The Android Open Source Project |
| |
| Licensed under the Apache License, Version 2.0 (the "License"); |
| you may not use this file except in compliance with the License. |
| You may obtain a copy of the License at |
| |
| http://www.apache.org/licenses/LICENSE-2.0 |
| |
| Unless required by applicable law or agreed to in writing, software |
| distributed under the License is distributed on an "AS IS" BASIS, |
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| See the License for the specific language governing permissions and |
| limitations under the License. |
| --> |
| |
| |
| |
| <p>Android 7.0 refactored the Radio Interface Layer (RIL) using a set of |
| features to improve RIL functionality. Partner code changes are required to |
| implement these features, which are optional but encouraged. Refactoring changes |
| are backward compatible, so prior implementations of the refactored features |
| continue to work.</p> |
| |
| <p>RIL refactoring includes the following improvements:</p> |
| |
| <ul> |
| <li><strong>RIL error codes.</strong> Enables specific error codes |
| in addition to the existing <code>GENERIC_FAILURE</code> code. This aids in |
| error troubleshooting by providing more specific information about the cause of |
| errors.</li> |
| <li><strong>RIL versioning.</strong> Provides more accurate and easier |
| to configure version information.</li> |
| <li><strong>RIL communication using wakelocks.</strong> Improves |
| device battery performance.</li> |
| </ul> |
| |
| <p>You can implement any or all of the above improvements. For more details, |
| refer to code comments on RIL versioning in |
| <a href="https://android.googlesource.com/platform/hardware/ril/+/master/include/telephony/ril.h"><code>https://android.googlesource.com/platform/hardware/ril/+/master/include/telephony/ril.h</code></a>.</p> |
| |
| <h2 id="errorcodes">Implementing enhanced RIL error codes</h2> |
| |
| <p>Almost all RIL request calls can return the <code>GENERIC_FAILURE</code> |
| error code in response to an error. This is an issue with all solicited |
| responses returned by the OEMs, which can make it difficult to debug an issue |
| from the bug report if the same <code>GENERIC_FAILURE</code> error code is |
| returned by RIL calls for different reasons. It can take considerable time |
| for vendors to even identify what part of the code could have returned a |
| <code>GENERIC_FAILURE</code> code.</p> |
| |
| <p>In Android 7.x and higher, OEMs can return a distinct error code value |
| associated with each different error that is currently categorized as |
| <code>GENERIC_FAILURE</code>. OEMs that do not want to publicly reveal their |
| custom error codes can return errors as a distinct set of integers (such as 1 to |
| x) mapped as <code>OEM_ERROR_1</code> to <code>OEM_ERROR_X</code>. Vendors |
| should ensure each such masked error code returned maps to a unique error reason |
| in the code. Using specific error codes can speed up RIL debugging whenever |
| generic errors are returned by the OEM, as it can often take too much time to |
| identify the exact cause of a <code>GENERIC_FAILURE</code> error code (and |
| sometimes it's impossible to figure out).<p> |
| |
| <p>In addition, <code>ril.h</code> adds more error codes for the enums |
| <code>RIL_LastCallFailCause</code> and <code>RIL_DataCallFailCause</code> so |
| vendor code can avoid returning generic errors such as |
| <code>CALL_FAIL_ERROR_UNSPECIFIED</code> and |
| <code>PDP_FAIL_ERROR_UNSPECIFIED</code>.</p> |
| |
| <h3 id="validate-error">Validating enhanced RIL error codes</h3> |
| |
| <p>After adding new error codes to replace the <code>GENERIC_FAILURE</code> |
| code, verify the new error codes are returned by the RIL call instead |
| of <code>GENERIC_FAILURE</code>.</p> |
| |
| <h2 id="version">Implementing enhanced RIL versioning</h2> |
| |
| <p>RIL versioning in older Android releases was problematic: the version itself |
| was imprecise, the mechanism for reporting a RIL version was unclear (causing |
| some vendors to report an incorrect version), and the workaround for estimating |
| the version was prone to inaccuracy.</p> |
| |
| <p>In Android 7.x and higher, <code>ril.h</code> documents all RIL version |
| values, describes the corresponding RIL version, and lists all changes for that |
| version. When making changes that correspond to a RIL version, vendors must |
| update their version in code and return that version in |
| <code>RIL_REGISTER</code>.</p> |
| |
| <h3 id="validate-version">Validating enhanced RIL versioning</h3> |
| |
| <p>Verify that the RIL version corresponding to your RIL code is returned |
| during <code>RIL_REGISTER</code> (rather than the <code>RIL_VERSION</code> |
| defined in <code>ril.h</code>).</p> |
| |
| <h2 id="wakelocks">Implementing RIL communication using wakelocks</h2> |
| |
| <p>Timed wakelocks are used in RIL communication in an imprecise way, |
| which negatively affects battery performance. In Android 7.x and higher, you can |
| improve performance by classifying RIL requests and updating code to handle |
| wakelocks differently for different request types.</p> |
| |
| <h3 id="classifying">Classifying RIL requests</h3> |
| <p>RIL requests can be either solicited or unsolicited. Vendors should further |
| classify solicited requests as one of the following:</p> |
| |
| <ul> |
| <li><strong>synchronous</strong>. Requests that do not take considerable time to |
| respond back. For example, <code>RIL_REQUEST_GET_SIM_STATUS</code>.</li> |
| <li><strong>asynchronous</strong>. Requests that take considerable time to |
| respond back. For example, <code>RIL_REQUEST_QUERY_AVAILABLE_NETWORKS</code>. |
| </li> |
| </ul> |
| |
| <p>Asynchronous solicited RIL requests can take considerable time. After |
| receiving an ack from vendor code, RIL Java releases the wakelock, which might |
| cause the application processor to go from idle to suspend state. When the |
| response is available from vendor code, RIL Java (the application processor) |
| re-acquires the wakelock, processes the response, then returns to idle. Such |
| moving from idle to suspend to idle can consume a lot of power.</p> |
| |
| <p>If the response time isn't long enough, holding the wakelock and staying in |
| idle for the entire time it takes to respond can be more power efficient than |
| going into suspend state by releasing the wakelock and waking when the response |
| arrives. Vendors should use platform-specific power measurements to determine |
| the threshold value of time <var>T</var> when the power consumed by |
| staying in idle for the entire time <var>T</var> is greater than the power |
| consumed by moving from idle to suspend and to idle in same time <var>T</var>. |
| When time <var>T</var> is known, RIL commands that take more than time |
| <var>T</var> can be classified as asynchronous and the remaining commands |
| classified as synchronous.</p> |
| |
| <h3 id="ril-comm-scenarios">RIL communication scenarios</h3> |
| <p>The following diagrams illustrate common RIL communication scenarios and |
| provide solutions for modifying code to handle RIL solicited and unsolicited |
| requests.</p> |
| |
| <p class="note"><strong>Note:</strong> For implementation details on functions |
| used in the following diagrams, refer to the <code>acquireWakeLock()</code>, |
| <code>decrementWakeLock()</code>, and <code>clearWakeLock(</code>) methods in |
| <code>ril.cpp</code>.</p> |
| |
| <h4>Scenario: RIL request and solicited asynchronous response</h4> |
| |
| <p>In this scenario, if the RIL solicited response is expected to take |
| considerable time (i.e. a response to |
| <code>RIL_REQUEST_GET_AVAILABLE_NETWORKS</code>), the wakelock is held for a |
| long time on the application processor side. Modem problems can also result in a |
| long wait.</p> |
| |
| <p><img src="images/ril-refactor-scenario-1.png"></p> |
| <figcaption><strong>Figure 1.</strong> RIL solicited asynchronous |
| response.</figcaption> |
| |
| <p><strong>Solution 1:</strong> The modem holds the wakelock for the RIL request |
| and asynchronous response.</p> |
| |
| <p><img src="images/ril-refactor-scenario-1-solution-1.png"></p> |
| <figcaption><strong>Figure 2.</strong> Wakelock held by modem.</figcaption> |
| |
| <ol> |
| <li>RIL request is sent and the modem acquires wakelock to process that |
| request.</li> |
| <li>Modem sends acknowledgement that causes the Java side to decrement |
| the wakelock counter and release it when the counter value is 0. |
| <p class="note"><strong>Note:</strong> The wakelock timeout duration for the |
| request-ack sequence would be smallerthan the currently used timeout duration |
| because the ack should be received fairly quickly.</p> |
| </li> |
| <li>After processing the request, the modem sends an interrupt to the vendor |
| code that acquires wakelock and sends a response to ril.cpp, which in turn |
| acquires wakelock and sends a response to the Java side.</li> |
| <li>When the response reaches the Java side, wakelock is acquired and a response |
| is returned to the caller.</li> |
| <li>After the response is processed by all modules, acknowledgement is |
| sent (via socket) back to <code>ril.cpp</code>, which then releases the wakelock |
| acquired in step 3.</li> |
| </ol> |
| |
| <p><strong>Solution 2:</strong> The modem does not hold the wakelock and the |
| response is quick (synchronous RIL request and response). The synchronous vs. |
| asynchronous behavior is hardcoded for a specific RIL command and decided on a |
| call-by-callbasis.</p> |
| |
| <p><img src="images/ril-refactor-scenario-1-solution-2.png"></p> |
| <figcaption><strong>Figure 3.</strong> Wakelock not held by modem.</figcaption> |
| |
| <ol> |
| <li>RIL request is sent by calling <code>acquireWakeLock()</code> on the |
| Java side.</li> |
| <li>Vendor code doesn't need to acquire wakelock and can process the request |
| and respond quickly.</li> |
| <li>When the response is received by the Java side, |
| <code>decrementWakeLock()</code> is called, which decreases wakelock counter |
| and releases wakelock if the counter value is 0.</li> |
| </ol> |
| |
| <h4>Scenario: RIL unsolicited response</h4> |
| <p>In this scenario, RIL unsolicited responses have a wakelock type flag in the |
| that indicates whether a wakelock needs to be acquired for the vendor response. |
| If the flag is set, a timed wakelock is set and the response is sent over a |
| socket to the Java side. When the timer expires, the wakelock is released. The |
| timed wakelock could be too long or too short for different RIL unsolicited |
| responses.</p> |
| |
| <p><img src="images/ril-refactor-scenario-2.png"></p> |
| <figcaption><strong>Figure 4.</strong> RIL unsolicited response.</figcaption> |
| |
| <p><strong>Solution:</strong> An acknowledgement is sent from the Java code to |
| the native side (<code>ril.cpp</code>) instead of holding a timed wakelock on |
| the native side while sending an unsolicited response.</p> |
| |
| <p><img src="images/ril-refactor-scenario-2-solution.png"></p> |
| <figcaption><strong>Figure 5.</strong> Using ack instead of timed wakelock. |
| </figcaption> |
| |
| |
| <h3 id="validate-wakelocks">Validating redesigned wakelocks</h3> |
| |
| <p>Verify that RIL calls are identified as synchronous or asynchronous. Because |
| battery power consumption can be hardware/platform dependent, vendors should do |
| some internal testing to find out if using the new wakelock semantics for |
| asynchronous calls leads to battery power savings.</p> |
| |
| </body> |
| </html> |