Add ExtensionManifestV2Availability policy definition

Add policy yaml definition and policy to pref mapping. This policy
will allow admin test manifest v2 deprecation ahead of time. It will
also allow for extend the manifest v2 support after its full deprecation
in the future.

Bug: 1347794
Change-Id: I9dd8c933a08d59cfe3898d7a2317b59ba9563422
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4004453
Commit-Queue: Owen Min <zmin@chromium.org>
Reviewed-by: Artem Sumaneev <asumaneev@google.com>
Reviewed-by: Julian Pastarmov <pastarmovj@chromium.org>
Reviewed-by: Istiaque Ahmed <lazyboy@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1070527}
diff --git a/chrome/browser/policy/configuration_policy_handler_list_factory.cc b/chrome/browser/policy/configuration_policy_handler_list_factory.cc
index 3f6c5ca..1eca6ac 100644
--- a/chrome/browser/policy/configuration_policy_handler_list_factory.cc
+++ b/chrome/browser/policy/configuration_policy_handler_list_factory.cc
@@ -1667,6 +1667,12 @@
     base::Value::Type::BOOLEAN },
 #endif // !BUILDFLAG(IS_CHROMEOS) && BUILDFLAG(ENABLE_EXTENSIONS)
 
+#if BUILDFLAG(ENABLE_EXTENSIONS)
+  { key::kExtensionManifestV2Availability,
+    extensions::pref_names::kManifestV2Availability,
+    base::Value::Type::INTEGER },
+#endif // BUILDFLAG(ENABLE_EXTENSIONS)
+
 #if BUILDFLAG(CHROME_ROOT_STORE_POLICY_SUPPORTED)
   { key::kChromeRootStoreEnabled,
     prefs::kChromeRootStoreEnabled,
diff --git a/chrome/test/data/policy/policy_test_cases.json b/chrome/test/data/policy/policy_test_cases.json
index be9af0e..162e188c 100644
--- a/chrome/test/data/policy/policy_test_cases.json
+++ b/chrome/test/data/policy/policy_test_cases.json
@@ -3780,6 +3780,67 @@
       }
     ]
   },
+  "ExtensionManifestV2Availability": {
+    "os": [
+      "win",
+      "linux",
+      "mac",
+      "chromeos_ash",
+      "crhomeos_lacros",
+      "fuchsia"
+    ],
+    "policy_pref_mapping_tests": [
+      {
+        "policies": {
+          "ExtensionManifestV2Availability": 0
+        },
+        "prefs": {
+          "extensions.manifest_v2": {
+            "value": 0
+          }
+        }
+      },
+      {
+        "policies": {
+          "ExtensionManifestV2Availability": 1
+        },
+        "prefs": {
+          "extensions.manifest_v2": {
+            "value": 1
+          }
+        }
+      },
+      {
+        "policies": {
+          "ExtensionManifestV2Availability": 2
+        },
+        "prefs": {
+          "extensions.manifest_v2": {
+            "value": 2
+          }
+        }
+      },
+      {
+        "policies": {
+          "ExtensionManifestV2Availability": 3
+        },
+        "prefs": {
+          "extensions.manifest_v2": {
+            "value": 3
+          }
+        }
+      },
+      {
+        "policies": {
+        },
+        "prefs": {
+          "extensions.manifest_v2": {
+            "default_value": 0
+          }
+        }
+      }
+    ]
+  },
   "BlockExternalExtensions": {
     "os": [
       "win",
diff --git a/components/policy/resources/templates/policies.yaml b/components/policy/resources/templates/policies.yaml
index 10de168..0e8614b 100644
--- a/components/policy/resources/templates/policies.yaml
+++ b/components/policy/resources/templates/policies.yaml
@@ -1028,6 +1028,7 @@
   1027: LensDesktopNTPSearchEnabled
   1028: AccessControlAllowMethodsInCORSPreflightSpecConformant
   1029: AllowWebAuthnWithBrokenTlsCerts
+  1030: ExtensionManifestV2Availability
 atomic_groups:
   1: Homepage
   2: RemoteAccess
diff --git a/components/policy/resources/templates/policy_definitions/Extensions/ExtensionManifestV2Availability.yaml b/components/policy/resources/templates/policy_definitions/Extensions/ExtensionManifestV2Availability.yaml
new file mode 100644
index 0000000..0b08ef66
--- /dev/null
+++ b/components/policy/resources/templates/policy_definitions/Extensions/ExtensionManifestV2Availability.yaml
@@ -0,0 +1,49 @@
+owners:
+- zmin@chromium.org
+- file://components/policy/OWNERS
+caption: Control manifest v2 extension availability.
+desc: |-
+  Control if manifest v2 extensions can be used by browser.
+
+  Manifest v2 extensions support will be deprecated and all extensions need
+  to be migrated to v3 in the future. More information and timeline of the
+  migration can be found at https://developer.chrome.com/docs/extensions/mv3/mv2-sunset/.
+
+  If the policy is set to <ph name="DEFAULT">Default</ph> (0) or not set, v2 extensions loading are decided by browser, following the timeline above.
+  If the policy is set to <ph name="DISABLE">Disable</ph> (1), v2 extensions installation are blocked, existing ones are disabled. The option is going to be treated the same as if the policy is not set after v2 support is turned off by default.
+  If the policy is set to <ph name="ENABLE">Enable</ph> (2), v2 extensions are allowed. The option is going to be treated the same as if the policy is not set before v2 support is turned off by default.
+  If the policy is set to <ph name="ENABLE_FOR_FORCED_EXTENSIONS">EnableForForcedExtensions</ph> (3), force installed v2 extensions are allowed. This includes extensions that are listed by <ph name="EXTENSION_INSTALL_FORCELIST_POLICY_NAME">ExtensionInstallForcelist</ph> or <ph name="EXTENSION_SETTINGS_POLICY_NAME">ExtensionSettings</ph> with <ph name="INSTALLATION_MODE">installation_mode</ph> "force_installed" or "normal_installed". All other v2 extensions are disabled. The option is going to be treated the same as if the policy is not set before v2 support is turned off by default.
+
+
+  Extensions availability are still controlled by other policies.
+future_on:
+- chrome.*
+- chrome_os
+- fuchsia
+features:
+  dynamic_refresh: true
+  per_profile: true
+type: int-enum
+schema:
+   type: integer
+   enum:
+   - 0
+   - 1
+   - 2
+   - 3
+items:
+- caption: Default browser behavior
+  name: Default
+  value: 0
+- caption: Manifest v2 is disabled
+  name: Disable
+  value: 1
+- caption: Manifest v2 is enabled
+  name: Enable
+  value: 2
+- caption: Manifest v2 is enabled for forced extensions only
+  name: EnableForForcedExtensions
+  value: 3
+default: 0
+example_value: 2
+tags: []
diff --git a/components/policy/resources/templates/policy_definitions/Extensions/policy_atomic_groups.yaml b/components/policy/resources/templates/policy_definitions/Extensions/policy_atomic_groups.yaml
index 0f93084f..7246e0fc 100644
--- a/components/policy/resources/templates/policy_definitions/Extensions/policy_atomic_groups.yaml
+++ b/components/policy/resources/templates/policy_definitions/Extensions/policy_atomic_groups.yaml
@@ -8,3 +8,4 @@
   - ExtensionAllowedTypes
   - ExtensionAllowInsecureUpdates
   - ExtensionSettings
+  - ExtensionManifestV2Availability
diff --git a/extensions/browser/extension_prefs.cc b/extensions/browser/extension_prefs.cc
index f874b0a1..fc03065 100644
--- a/extensions/browser/extension_prefs.cc
+++ b/extensions/browser/extension_prefs.cc
@@ -2263,6 +2263,7 @@
   registry->RegisterListPref(pref_names::kInstallDenyList);
   registry->RegisterDictionaryPref(pref_names::kInstallForceList);
   registry->RegisterListPref(pref_names::kAllowedTypes);
+  registry->RegisterIntegerPref(pref_names::kManifestV2Availability, 0);
   registry->RegisterBooleanPref(pref_names::kStorageGarbageCollect, false);
   registry->RegisterListPref(pref_names::kAllowedInstallSites);
   registry->RegisterStringPref(pref_names::kLastChromeVersion, std::string());
diff --git a/extensions/browser/pref_names.cc b/extensions/browser/pref_names.cc
index 2275a88..59c7f809 100644
--- a/extensions/browser/pref_names.cc
+++ b/extensions/browser/pref_names.cc
@@ -43,6 +43,7 @@
 const char kNativeMessagingAllowlist[] = "native_messaging.whitelist";
 const char kNativeMessagingUserLevelHosts[] =
     "native_messaging.user_level_hosts";
+const char kManifestV2Availability[] = "extensions.manifest_v2";
 const char kPinnedExtensions[] = "extensions.pinned_extensions";
 const char kStorageGarbageCollect[] = "extensions.storage.garbagecollect";
 const char kDeletedComponentExtensions[] =
diff --git a/extensions/browser/pref_names.h b/extensions/browser/pref_names.h
index 560c9ac..2ea0bec 100644
--- a/extensions/browser/pref_names.h
+++ b/extensions/browser/pref_names.h
@@ -85,6 +85,11 @@
 // Time of the next scheduled extensions auto-update checks.
 extern const char kNextUpdateCheck[];
 
+// An integer indicates the availability of manifest v2 extensions. The value is
+// controlled by the ExtensionManifestV2Availability policy. More details can
+// be found at ExtensionManifestV2Availability.yaml.
+extern const char kManifestV2Availability[];
+
 // A preference that tracks extensions pinned to the toolbar. This is a list
 // object stored in the Preferences file. The extensions are stored by ID.
 extern const char kPinnedExtensions[];
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index fc9cf03..9290499 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -33422,6 +33422,7 @@
   <int value="1028"
       label="AccessControlAllowMethodsInCORSPreflightSpecConformant"/>
   <int value="1029" label="AllowWebAuthnWithBrokenTlsCerts"/>
+  <int value="1030" label="ExtensionManifestV2Availability"/>
 </enum>
 
 <enum name="EnterprisePoliciesSources">