Watchdog 會追蹤所有應用程式和服務的磁碟 I/O 寫入總量,藉此監控快閃記憶體用量,方法是使用 Kernel 在 `/proc/uid_io/stats` 位置公開的每個 UID 磁碟 I/O 統計資料。當應用程式或服務超過磁碟 I/O 過度使用門檻時,Watchdog 會對該應用程式或服務採取行動。磁碟 I/O 使用過度門檻和使用過度時採取的動作,都已在磁碟 I/O 使用過度設定中預先定義。
過度使用門檻
- 系統每天都會強制執行磁碟 I/O 用量過度上限,也就是說,系統會從目前世界標準時間日曆日開始,彙整應用程式/服務的所有寫入作業,並根據用量過度設定中定義的上限進行檢查。
- 如果車輛在特定日期多次啟動,Watchdog 模組會將磁碟 I/O 使用率統計資料儲存在快閃記憶體中,並從當天 UTC 日曆日開始彙整資料。
過度使用動作
如果應用程式持續超出定義的磁碟 I/O 過度使用門檻,Watchdog 會採取過度使用設定中定義的動作。
- 所有供應商應用程式和服務都視為整體系統穩定性的關鍵,因此不會因磁碟 I/O 使用過度而終止。不過,過度使用設定可以定義可安全終止的供應商應用程式和服務清單。
- 所有第三方應用程式都可以安全終止。
如果應用程式或服務可安全終止,Watchdog 會使用應用程式元件狀態
PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED
停用該應用程式或服務。
過度使用設定
過度使用設定包含磁碟 I/O 過度使用門檻和動作。系統和供應商映像檔會定義預設的過度使用設定,並隨建構作業一併出貨。供應商可選擇在供應商映像檔中加入供應商設定。如果未提供供應商設定,系統也會將系統設定用於供應商應用程式和服務。
Watchdog 會透過 CarWatchdogManager
公開系統 API,讓供應商應用程式或服務隨時更新供應商設定。
過度使用設定定義
過度使用設定會依元件類型 (例如系統、供應商和第三方) 分類。原始設備製造商只能更新供應商元件設定。
供應商設定
供應商設定會為所有供應商應用程式和服務,以及所有地圖和媒體應用程式,定義磁碟 I/O 使用過度門檻和動作。設定包含下列設定欄位。
- 供應商套件前置字串:凡是安裝在供應商分割區中的套件,都視為供應商套件。除了這些套件,供應商也可以將預先安裝的套件分類為供應商套件,方法是將套件前置字元新增至「供應商套件前置字元」設定。這項設定不接受規則運算式。
- 可安全終止的套件。供應商可以將完整的套件名稱新增至「safe-to-terminate packages」設定,指定哪些供應商套件可安全終止。
- 應用程式類別對應:供應商可將任何套件 (包括第三方套件) 對應至兩個支援的應用程式類別之一:地圖和媒體應用程式。進行這項對應作業,是為了讓地圖和媒體應用程式的磁碟 I/O 過度使用閾值更高,因為這類應用程式往往會比其他類型的應用程式下載及寫入更多資料到磁碟。
- 元件層級門檻。為所有供應商套件定義一般門檻 (也就是說,未涵蓋在「套件專屬門檻」或「應用程式類別專屬門檻」中的套件會取得這些門檻)。定義磁碟 I/O 使用過度設定時,供應商必須定義非零的元件層級門檻。
- 套裝方案專屬門檻。供應商可以為特定供應商套裝組合定義特殊門檻。對應項目應包含完整的套件名稱。這個設定中定義的門檻優先於特定套件其他設定中定義的門檻。
- 應用程式類別專屬門檻。供應商可以為特定應用程式類別指定特殊門檻。應用程式類別必須是支援的類別,例如地圖和媒體應用程式。這項設定中定義的門檻會使用應用程式類別對應,對應至特定套件。
- 全系統門檻。供應商不得指定這項設定。
供應商套件前置字元、可安全終止的套件、元件層級門檻和套件專屬門檻設定,只能透過供應商應用程式和服務的供應商設定更新。只有所有地圖和媒體應用程式的供應商設定,才能更新應用程式類別專屬的門檻設定。
過度使用門檻包含在下列時間內可寫入的位元組數:
- 應用程式或服務的前景模式與背景模式
- 系統車庫模式
這項分類可讓面向使用者的前景應用程式和服務寫入的資料量,多於背景應用程式和服務。應用程式和服務通常會在車庫模式中下載更新,因此需要比在其他模式中執行的應用程式和服務更高的門檻。
系統和第三方設定
原始設備製造商不應更新系統和第三方設定。
- 系統設定會定義系統應用程式和服務的 I/O 使用過度門檻和動作。
- 這項設定也可以更新應用程式類別對應。因此,這個設定欄位會在系統和供應商設定之間共用。
- 第三方設定會為所有第三方應用程式定義門檻。系統預先安裝的應用程式以外,都是第三方應用程式。
- 所有第三方應用程式都會收到相同的門檻 (例如,第三方應用程式不會收到特殊門檻),但地圖和媒體應用程式除外,這類應用程式的門檻是由供應商設定定義。
- 下列磁碟 I/O 使用過度門檻是第三方應用程式的預設門檻。這些門檻會隨附於系統映像檔。
- 在應用程式前景模式下寫入 3 GB。
- 在應用程式背景模式中寫入 2 GiB。
- 在系統車庫模式中寫入 4 GiB。
- 這些是基本門檻。隨著我們對磁碟 I/O 使用量的瞭解越深入,這些門檻也會隨之更新。
過度使用設定 XML 格式
預設供應商設定可以放在建構映像檔的 /vendor/etc/automotive/watchdog/resource_overuse_configuration.xml
位置 (選用)。如果未指定這項設定,系統定義的設定也會套用至供應商應用程式和服務。
XML 檔案的每個設定欄位只能包含一個標記。I/O 過度使用 設定必須在 XML 檔案中定義。所有門檻值都應以 MiB 為單位指定。
以下提供 XML 設定範例:
<resourceOveruseConfiguration version="1.0"> <componentType>VENDOR</componentType> <!-- List of safe to kill vendor packages. --> <safeToKillPackages> <package>com.vendor.package.A</package> <package>com.vendor.package.B</package> </safeToKillPackages> <!-- List of vendor package prefixes. --> <vendorPackagePrefixes> <packagePrefix>com.vendor.package</packagePrefix> </vendorPackagePrefixes> <!-- List of unique package names to app category mappings. --> <packagesToAppCategoryTypes> <packageAppCategory type="MEDIA">com.vendor.package.A</packageAppCategory> <packageAppCategory type="MAPS">com.google.package.B</packageAppCategory> <packageAppCategory type="MEDIA">com.third.party.package.C</packageAppCategory> </packagesToAppCategoryTypes> <ioOveruseConfiguration> <!-- Thresholds in MiB for all vendor packages that don't have package specific thresholds. --> <componentLevelThresholds> <state id="foreground_mode">1024</state> <state id="background_mode">512</state> <state id="garage_mode">3072</state> </componentLevelThresholds> <packageSpecificThresholds> <!-- IDs must be unique --> <perStateThreshold id="com.vendor.package.C"> <state id="foreground_mode">400</state> <state id="background_mode">100</state> <state id="garage_mode">200</state> </perStateThreshold> <perStateThreshold id="com.vendor.package.D"> <state id="foreground_mode">1024</state> <state id="background_mode">500</state> <state id="garage_mode">2048</state> </perStateThreshold> </packageSpecificThresholds> <!-- Application category specific thresholds. --> <appCategorySpecificThresholds> <!-- One entry per supported application category --> <perStateThreshold id="MEDIA"> <state id="foreground_mode">600</state> <state id="background_mode">700</state> <state id="garage_mode">1024</state> </perStateThreshold> <perStateThreshold id="MAPS"> <state id="foreground_mode">800</state> <state id="background_mode">900</state> <state id="garage_mode">2048</state> </perStateThreshold> </appCategorySpecificThresholds> </ioOveruseConfiguration> </resourceOveruseConfiguration>
透過 CarWatchdogManager 系統 API 更新過度使用設定
上述 XML 設定只能在建構映像檔中提供。如果 OEM 選擇在版本發布後更新裝置端設定,可以使用下列 API 變更裝置端設定。
- 授予來電者
Car.PERMISSION_CONTROL_CAR_WATCHDOG_CONFIG
權限。 - 必須使用現有設定來更新及設定新設定。使用 API
CarWatchdogManager.getResourceOveruseConfigurations
取得現有設定。如果未使用現有設定,所有設定 (包括系統和第三方設定) 都會遭到覆寫,因此不建議這麼做。 - 使用差異變更更新現有設定,並設定新的設定。請勿更新系統和第三方元件設定。
- 使用 API
CarWatchdogManager.setResourceOveruseConfigurations
設定新設定。 - 如要取得及設定磁碟 I/O 過度使用設定,請使用
CarWatchdogManager.FLAG_RESOURCE_OVERUSE_IO
標記。
以下是更新資源過度使用設定的實作範例:
void updateResourceOveruseConfigurations() { CarWatchdogManager manager = (CarWatchdogManager) car.getCarManager(Car.CAR_WATCHDOG_SERVICE); List<ResourceOveruseConfiguration> resourceOveruseConfigurations = manager.getResourceOveruseConfigurations( CarWatchdogManager.FLAG_RESOURCE_OVERUSE_IO); List<ResourceOveruseConfiguration> newResourceOveruseConfigurations = new List<>(); ResourceOveruseConfiguration vendorConfiguration; for(ResourceOveruseConfiguration config : resourceOveruseConfigurations) { // Do not update the configurations of the system and third-party component types. if (config.getComponentType() != ResourceOveruseConfiguration.COMPONENT_TYPE_VENDOR) { newResourceOveruseConfigurations.add(config); continue; } vendorConfiguration = config; } if (vendorConfiguration == null) { ResourceOveruseConfiguration.Builder vendorConfigBuilder = new ResourceOveruseConfiguration.Builder(); initializeConfig(vendorConfigBuilder); newResourceOveruseConfigurations.add(vendorConfigBuilder.build()); } else { ResourceOveruseConfiguration newVendorConfig = updateConfig(vendorConfiguration); newResourceOveruseConfigurations.add(newVendorConfig); } int result = manager.setResourceOveruseConfigurations( newResourceOveruseConfigurations, if (result != CarWatchdogManager.RETURN_CODE_SUCCESS) { // Failed to set the resource overuse configurations. } } /** Sets the delta between the old configuration and the new configuration. */ ResourceOveruseConfiguration updateConfig( ResourceOveruseConfiguration oldConfiguration) { // Replace com.vendor.package.A with com.vendor.package.B in the safe-to-kill list. List<String> safeToKillPackages = oldConfiguration.getSafeToKillPackages(); safeToKillPackages.remove("com.vendor.package.A"); safeToKillPackages.add("com.vendor.package.B"); ResourceOveruseConfiguration.Builder configBuilder = new ResourceOveruseConfiguration.Builder( oldConfiguration.getComponentType(), safeToKillPackages, oldConfiguration.getVendorPackagePrefixes(), oldConfiguration.getPackagesToAppCategoryTypes()); configBuilder.addVendorPackagePrefixes("com.vendor."); configBuilder.addPackagesToAppCategoryTypes("com.vendor.package.B", ResourceOveruseConfiguration.APPLICATION_CATEGORY_TYPE_MAPS); IoOveruseConfiguration oldIoConfiguration = oldConfiguration.getIoOveruseConfiguration(); IoOveruseConfiguration.Builder ioConfigBuilder = new IoOveruseConfiguration.Builder( oldIoConfiguration.getComponentLevelThresholds(), oldIoConfiguration.getPackageSpecificThresholds(), oldIoConfiguration.getAppCategorySpecificThresholds(), oldIoConfiguration.getSystemWideThresholds()); // Define the amount of bytes based on the flash memory specification, expected lifetime, // and estimated average amount of bytes written by a package during different modes. ioConfigBuilder.addPackageSpecificThresholds("com.vendor.package.B", new PerStateBytes(/* foregroundModeBytes= */ 2 * 1024 * 1024 * 1024, /* backgroundModeBytes= */ 500 * 1024 * 1024, /* garageModeBytes= */ 3 * 1024 * 1024 * 1024)); return configBuilder.setIoOveruseConfiguration(ioConfigBuilder.build()).build(); }
監控資源用量過高的應用程式
供應商和第三方應用程式可以監聽 Watchdog 傳送的應用程式專屬資源過度使用通知,或輪詢 CarWatchdogManager
,取得過去 30 天的應用程式專屬資源過度使用統計資料。
接收資源用量過度通知
應用程式可以實作資源過度使用監聽器,並向 CarWatchdogManager
註冊監聽器,在超過磁碟 I/O 過度使用閾值的 80% 或 100% 時,接收應用程式專屬通知。應用程式可使用這些通知執行下列操作:
- 記錄磁碟 I/O 使用過度統計資料,以供離線分析。應用程式開發人員可使用這項記錄功能,找出磁碟 I/O 使用過度的問題。
- 減少磁碟 I/O 寫入次數,直到過度使用計數器重設為止。
Java 用戶端
- 透過繼承
CarWatchdogManager.ResourceOveruseListener
實作監聽器:class ResourceOveruseListenerImpl implements CarWatchdogManager.ResourceOveruseListener { @Override public void onOveruse( @NonNull ResourceOveruseStats resourceOveruseStats) { // 1. Log/Upload resource overuse metrics. // 2. Reduce writes until the counters reset. IoOveruseStats ioOveruseStats = resourceOveruseStats.getIoOveruseStats(); // Stats period - [ioOveruseStats.getStartTime(), ioOveruseStats.getStartTime() // + ioOveruseStats.getDurationInSeconds()] // Total I/O overuses - ioOveruseStats.getTotalOveruses() // Total bytes written - ioOveruseStats.getTotalBytesWritten() // Remaining write bytes for the current UTC calendar day - // ioOveruseStats.getRemainingWriteBytes() } } }
- 呼叫
CarWatchdogManager.addResourceOveruseListener
註冊事件監聽器例項private void addResourceOveruseListener() { CarWatchdogManager manager = (CarWatchdogManager) car.getCarManager(Car.CAR_WATCHDOG_SERVICE); // Choose a proper executor to handle resource overuse notifications. Executor executor = mContext.getMainExecutor(); manager.addResourceOveruseListener( executor, CarWatchdogManager.FLAG_RESOURCE_OVERUSE_IO, mListenerImpl); }
- 應用程式完成下列事項後,請取消註冊監聽器例項:
private void removeResourceOveruseListener() { CarWatchdogManager manager = (CarWatchdogManager) car.getCarManager(Car.CAR_WATCHDOG_SERVICE); mCarWatchdogManager.removeResourceOveruseListener( mListenerImpl); }
原生用戶端
- 在建構規則的
shared_libs
依附元件中加入carwatchdog_aidl_interface-ndk_platform
。Android.bp
cc_binary { name: "sample_native_client", srcs: [ "src/*.cpp" ], shared_libs: [ "carwatchdog_aidl_interface-ndk_platform", "libbinder_ndk", ], vendor: true, }
- 新增 SELinux 政策,允許供應商服務網域使用繫結器 (
binder_user
巨集),並將供應商服務網域新增至carwatchdog
用戶端網域(carwatchdog_client_domain macro)
。請參閱下方的sample_client.te
和file_contexts
程式碼。sample_client.te
type sample_client, domain; type sample_client_exec, exec_type, file_type, vendor_file_type; carwatchdog_client_domain(sample_client) init_daemon_domain(sample_client) binder_use(sample_client)
file_contexts
/vendor/bin/sample_native_client u:object_r:sample_client_exec:s0
- 如要實作資源過度使用監聽器,請繼承
BnResourceOveruseListener
。覆寫BnResourceOveruseListener::onOveruse
,處理資源用量過度通知。ResourceOveruseListenerImpl.h
class ResourceOveruseListenerImpl : public BnResourceOveruseListener { public: ndk::ScopedAStatus onOveruse( ResourceOveruseStats resourceOveruseStats) override; private: void initialize(); void terminate(); std::shared_ptr<ICarWatchdog> mWatchdogServer; std::shared_ptr<IResourceOveruseListener> mListener; }
ResourceOveruseListenerImpl.cpp
ndk::ScopedAStatus ResourceOveruseListenerImpl::onOveruse( ResourceOveruseStats resourceOveruseStats) { // 1. Log/Upload resource overuse metrics. // 2. Reduce writes until the counters reset. if (stats.getTag() != ResourceOveruseStats::ioOveruseStats) { // Received resourceOveruseStats doesn't contain I/O overuse stats. } const IoOveruseStats& ioOveruseStats = stats.get(); // Stats period - [ioOveruseStats.startTime, // ioOveruseStats.startTime + ioOveruseStats.durationInSeconds] // Total I/O overuses - ioOveruseStats.totalOveruses // Total bytes written - ioOveruseStats.writtenBytes // Remaining write bytes for the current UTC calendar day - // ioOveruseStats.remainingWriteBytes return ndk::ScopedAStatus::ok(); }
- 啟動繫結器執行緒集區,並向監控伺服器註冊資源過度使用監聽器。Watchdog 伺服器會註冊在服務名稱
android.automotive.watchdog.ICarWatchdog/default
下方。main.cpp
int main(int argc, char** argv) { ABinderProcess_setThreadPoolMaxThreadCount(1); ABinderProcess_startThreadPool(); std::shared_ptr<ResourceOveruseListenerImpl> listener = ndk::SharedRefBase::make<ResourceOveruseListenerImpl>(); // The listener is added in initialize(). listener->initialize(); ... Run service ... // The listener is removed in terminate(). listener->terminate(); }
ResourceOveruseListenerImpl.cpp
void ResourceOveruseListener::initialize() { ndk::SpAIBinder binder(AServiceManager_getService( "android.automotive.watchdog.ICarWatchdog/default")); std::shared_ptr<ICarWatchdog> server = ICarWatchdog::fromBinder(binder); mWatchdogServer = server; std::shared_ptr<IResourceOveruseListener> listener = IResourceOveruseListener::fromBinder(this->asBinder()); mWatchdogServer->addResourceOveruseListener( std::vector<int>{ResourceType.IO}, listener); mListener = listener; } void ResourceOveruseListener::terminate() { mWatchdogServer->removeResourceOveruseListener(mListener); }
輪詢資源過度使用統計資料
應用程式可以輪詢 CarWatchdogManager,取得最近 30 天的應用程式專屬 I/O 過度使用統計資料 ATS。
Java 用戶端
使用 CarWatchdogManager.getResourceOveruseStats
取得資源過度使用統計資料。傳遞 CarWatchdogManager.FLAG_RESOURCE_OVERUSE_IO
旗標,即可取得磁碟 I/O 使用過度統計資料。
private void getResourceOveruseStats() { CarWatchdogManager manager = (CarWatchdogManager) car.getCarManager(Car.CAR_WATCHDOG_SERVICE); // Returns resource overuse stats with I/O overuse stats for the past // 7 days. Stats are available for up to the past 30 days. ResourceOveruseStats resourceOveruseStats = mCarWatchdogManager.getResourceOveruseStats( CarWatchdogManager.FLAG_RESOURCE_OVERUSE_IO, CarWatchdogManager.STATS_PERIOD_PAST_7_DAYS); IoOveruseStats ioOveruseStats = resourceOveruseStats.getIoOveruseStats(); // Stats period - [ioOveruseStats.getStartTime(), ioOveruseStats.getStartTime() // + ioOveruseStats.getDurationInSeconds()] // Total I/O overuses - ioOveruseStats.getTotalOveruses() // Total bytes written - ioOveruseStats.getTotalBytesWritten() // Remaining write bytes for the UTC calendar day - // ioOveruseStats.getRemainingWriteBytes() }
原生用戶端
使用 CarWatchdogServer.getResourceOveruseStats
取得資源過度使用統計資料。傳遞 ResourceType.IO
列舉,即可擷取磁碟 I/O 過度使用統計資料。
void getResourceOveruseStats() { ndk::SpAIBinder binder(AServiceManager_getService( "android.automotive.watchdog.ICarWatchdog/default")); std::shared_ptr<ICarWatchdog> server = ICarWatchdog::fromBinder(binder); // Returns the stats only for the current UTC calendar day. const std::vector<ResourceOveruseStats> resourceOveruseStats; ndk::ScopedAStatus status = server.getResourceOveruseStats( std::vector<int>{ResourceType.IO}, &resourceOveruseStats); if (!status.isOk()) { // Failed to get the resource overuse stats. return; } for (const auto& stats : resourceOveruseStats) { if (stats.getTag() != ResourceOveruseStats::ioOveruseStats) { continue; } const IoOveruseStats& ioOveruseStats = stats.get(); // Stats period - [ioOveruseStats.startTime, // ioOveruseStats.startTime + ioOveruseStats.durationInSeconds] // Total I/O overuses - ioOveruseStats.totalOveruses // Total bytes written - ioOveruseStats.writtenBytes // Remaining write bytes for the current UTC calendar day - // ioOveruseStats.remainingWriteBytes } }
資源用量過高使用者體驗
以下各節說明資源過度使用時的使用者體驗。
應用程式效能優先設定
「設定」頁面包含 Prioritize app performance
的設定 (請見下圖),使用者可透過這些設定,優先考量應用程式效能,而非系統和長期硬體效能。這項設定僅適用於資源用量過高時可安全終止的應用程式。否則這項設定會停用。如果為應用程式關閉這項設定 (預設設定),應用程式可能會因資源用量過高而終止。否則,應用程式不會因資源過度使用而終止。
使用者開啟這項設定時,系統會顯示下列確認對話方塊,說明開啟這項設定的影響:
90 天後,這項設定會自動重設為預設值。使用 RRO 疊加應用程式,即可透過 watchdogUserPackageSettingsResetDays
修改天數上限,最多可延長至 180 天。詳情請參閱「在執行階段變更應用程式資源的值」。以下範例重疊標記可納入 AndroidManifest.xml
:
<overlay android:priority="<insert-value>" android:targetPackage="com.android.car.updatable" android:targetName="CarServiceCustomization" android:resourcesMap="@xml/overlays" />
在 res/values/config.xml
中:
<resources> <integer name="watchdogUserPackageSettingsResetDays">value</integer> </resources>
在 res/xml/overlays.xml
中:
<overlay> <item target="integer/watchdogUserPackageSettingsResetDays" value="@integer/watchdogUserPackageSettingsResetDays" /> </overlay>
影響效能的應用程式設定
「設定」應用程式包含「影響效能的應用程式」部分 (請參閱圖 1)。輕觸後,系統會顯示因過度使用快閃記憶體而受到限制,並對系統效能造成負面影響的應用程式清單。這符合 CDD 3.5.1 的 [C-1-1]要求。
圖 1. 影響效能的應用程式。
這裡會列出因資源用量過高而終止的應用程式 (請參閱圖 2)。你可以優先處理清單中的應用程式。詳情請參閱「優先處理應用程式效能設定」。
圖 2. 因資源用量過高而終止的應用程式清單。
使用者通知
如果應用程式或服務在特定時間內重複過度使用磁碟 I/O (例如寫入磁碟的資料超出定義的門檻),且可因資源用量過度而安全終止,系統會在車輛進入允許駕駛人分心狀態後通知使用者。
系統會在行車期間以抬頭通知的形式發布第一則使用者通知,其他通知則會發布在通知中心。
舉例來說,如果應用程式重複過度使用磁碟 I/O,使用者會收到以下通知:
- 使用者點選「優先處理應用程式」按鈕後,系統會啟動應用程式的設定頁面,使用者可以在該頁面開啟或關閉「優先處理應用程式效能」設定。
- 使用者點選「停用應用程式」按鈕後,應用程式就會停用,直到使用者啟動應用程式,或在應用程式的設定頁面啟用為止。
- 如果應用程式可以解除安裝,系統會以「解除安裝應用程式」按鈕取代「停用應用程式」按鈕。使用者點選「解除安裝應用程式」按鈕後,系統會啟動應用程式的「設定」頁面,使用者可從該頁面解除安裝應用程式。
啟動器實作建議
如果應用程式因資源用量過高而遭到停用,應用程式就會從預設啟動器應用程式中消失,因為 CarService 會將應用程式的啟用狀態更新為 PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED
。原始設備製造商必須更新內建啟動器實作項目,照常顯示這些應用程式,讓使用者在需要時使用。請參閱下列根據建構版本提供的建議。
Android SC V2 版本
- 啟動器實作項目在擷取要在啟動器上顯示的套件清單時,應使用
MATCH_DISABLED_UNTIL_USED_COMPONENTS
標記。 - 當使用者點選處於
PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED
狀態的應用程式時,啟動器應用程式必須將啟用狀態設為下列值,藉此啟用應用程式: